#@title Imports and Global Variables (make sure to run this cell) { display-mode: "form" } try: # %tensorflow_version only exists in Colab. %tensorflow_version 2.x except Exception: pass from __future__ import absolute_import, division, print_function #@markdown This sets the warning status (default is `ignore`, since this notebook runs correctly) warning_status = "ignore" #@param ["ignore", "always", "module", "once", "default", "error"] import warnings warnings.filterwarnings(warning_status) with warnings.catch_warnings(): warnings.filterwarnings(warning_status, category=DeprecationWarning) warnings.filterwarnings(warning_status, category=UserWarning) import numpy as np import os #@markdown This sets the styles of the plotting (default is styled like plots from [FiveThirtyeight.com](https://fivethirtyeight.com/) matplotlib_style = 'fivethirtyeight' #@param ['fivethirtyeight', 'bmh', 'ggplot', 'seaborn', 'default', 'Solarize_Light2', 'classic', 'dark_background', 'seaborn-colorblind', 'seaborn-notebook'] import matplotlib.pyplot as plt; plt.style.use(matplotlib_style) import matplotlib.axes as axes; from matplotlib.patches import Ellipse #%matplotlib inline import seaborn as sns; sns.set_context('notebook') from IPython.core.pylabtools import figsize #@markdown This sets the resolution of the plot outputs (`retina` is the highest resolution) notebook_screen_res = 'retina' #@param ['retina', 'png', 'jpeg', 'svg', 'pdf'] #%config InlineBackend.figure_format = notebook_screen_res import tensorflow as tf import tensorflow_probability as tfp tfd = tfp.distributions tfb = tfp.bijectors class _TFColor(object): """Enum of colors used in TF docs.""" red = '#F15854' blue = '#5DA5DA' orange = '#FAA43A' green = '#60BD68' pink = '#F17CB0' brown = '#B2912F' purple = '#B276B2' yellow = '#DECF3F' gray = '#4D4D4D' def __getitem__(self, i): return [ self.red, self.orange, self.green, self.blue, self.pink, self.brown, self.purple, self.yellow, self.gray, ][i % 9] TFColor = _TFColor() def session_options(enable_gpu_ram_resizing=True, enable_xla=False): """ Allowing the notebook to make use of GPUs if they're available. XLA (Accelerated Linear Algebra) is a domain-specific compiler for linear algebra that optimizes TensorFlow computations. """ config = tf.config gpu_devices = config.experimental.list_physical_devices('GPU') if enable_gpu_ram_resizing: for device in gpu_devices: tf.config.experimental.set_memory_growth(device, True) if enable_xla: config.optimizer.set_jit(True) return config session_options(enable_gpu_ram_resizing=True, enable_xla=True) # Build Graph rv_coin_flip_prior = tfp.distributions.Bernoulli(probs=0.5, dtype=tf.int32) num_trials = tf.constant([0,1, 2, 3, 4, 5, 8, 15, 50, 500, 1000, 2000]) coin_flip_data = rv_coin_flip_prior.sample(num_trials[-1]) # prepend a 0 onto tally of heads and tails, for zeroth flip coin_flip_data = tf.pad(coin_flip_data,tf.constant([[1, 0,]]),"CONSTANT") # compute cumulative headcounts from 0 to 2000 flips, and then grab them at each of num_trials intervals cumulative_headcounts = tf.gather(tf.cumsum(coin_flip_data), num_trials) rv_observed_heads = tfp.distributions.Beta( concentration1=tf.cast(1 + cumulative_headcounts, tf.float32), concentration0=tf.cast(1 + num_trials - cumulative_headcounts, tf.float32)) probs_of_heads = tf.linspace(start=0., stop=1., num=100, name="linspace") observed_probs_heads = tf.transpose(rv_observed_heads.prob(probs_of_heads[:, tf.newaxis])) # For the already prepared, I'm using Binomial's conj. prior. plt.figure(figsize(16, 9)) for i in range(len(num_trials)): sx = plt.subplot(len(num_trials)/2, 2, i+1) plt.xlabel("$p$, probability of heads") \ if i in [0, len(num_trials)-1] else None plt.setp(sx.get_yticklabels(), visible=False) plt.plot(probs_of_heads, observed_probs_heads[i], label="observe %d tosses,\n %d heads" % (num_trials[i], cumulative_headcounts[i])) plt.fill_between(probs_of_heads, 0, observed_probs_heads[i], color=TFColor[3], alpha=0.4) plt.vlines(0.5, 0, 4, color="k", linestyles="--", lw=1) leg = plt.legend() leg.get_frame().set_alpha(0.4) plt.autoscale(tight=True) plt.suptitle("Bayesian updating of posterior probabilities", y=1.02, fontsize=14) plt.tight_layout() # Defining our range of probabilities p = tf.linspace(start=0., stop=1., num=50) # Visualization. plt.figure(figsize=(12.5, 6)) plt.plot(p, 2*p/(1+p), color=TFColor[3], lw=3) #plt.fill_between(p, 2*p/(1+p), alpha=.5, facecolor=["#A60628"]) plt.scatter(0.2, 2*(0.2)/1.2, s=140, c=TFColor[3]) plt.xlim(0, 1) plt.ylim(0, 1) plt.xlabel(r"Prior, $P(A) = p$") plt.ylabel(r"Posterior, $P(A|X)$, with $P(A) = p$") plt.title(r"Are there bugs in my code?"); # Defining our priors and posteriors prior = tf.constant([0.20, 0.80]) posterior = tf.constant([1./3, 2./3]) # Our Simple Visualization plt.figure(figsize=(12.5, 4)) colours = [TFColor[0], TFColor[3]] plt.bar([0, .7], prior, alpha=0.70, width=0.25, color=colours[0], label="prior distribution", lw="3", edgecolor=colours[0]) plt.bar([0+0.25, .7+0.25], posterior, alpha=0.7, width=0.25, color=colours[1], label=r"posterior distribution", lw="3", edgecolor=colours[1]) plt.xticks([0.20, .95], ["Bugs Absent", "Bugs Present"]) plt.title(r"Prior and Posterior probability of bugs present") plt.ylabel("Probability") plt.legend(loc="upper left"); # Build graph. x = tf.range (start=0., limit=16.,dtype=tf.float32) lambdas = tf.constant([1.5, 4.25]) poi_pmf = tfd.Poisson( rate=lambdas[:, tf.newaxis]).prob(x) plt.figure(figsize=(12.5, 8)) # Display results in two different histograms, for easier comparison colours = [TFColor[0], TFColor[3]] for i in [0,1]: ax = plt.subplot(2,1,i+1) ax.set_autoscaley_on(False) plt.title("Probability mass function of a Poisson random variable"); plt.bar(x, poi_pmf[i], color=colours[i], label=r"$\lambda = %.1f$" % lambdas[i], alpha=0.60, edgecolor=colours[i], lw="3") plt.xticks(x) plt.ylim([0, .5]) plt.legend() plt.ylabel(r"probability of $k$") plt.xlabel(r"$k$") # Defining our Data and assumptions (use tf.linspace for continuous) a = tf.range(start=0., limit=4., delta=0.04) a = a[..., tf.newaxis] lambdas = tf.constant([0.5, 1.]) # Now we use TFP to compute probabilities in a vectorized manner. expo_pdf = tfd.Exponential(rate=lambdas).prob(a) # Visualizing our results plt.figure(figsize=(12.5, 4)) for i in range(lambdas.shape[0]): plt.plot(tf.transpose(a)[0], tf.transpose(expo_pdf)[i], lw=3, color=TFColor[i], label=r"$\lambda = %.1f$" % lambdas[i]) plt.fill_between(tf.transpose(a)[0], tf.transpose(expo_pdf)[i], color=TFColor[i], alpha=.33) plt.legend() plt.ylabel("PDF at $z$") plt.xlabel("$z$") plt.ylim(0,1.2) plt.title(r"Probability density function of an Exponential random variable; differing $\lambda$"); # Defining our Data and assumptions count_data = tf.constant([ 13, 24, 8, 24, 7, 35, 14, 11, 15, 11, 22, 22, 11, 57, 11, 19, 29, 6, 19, 12, 22, 12, 18, 72, 32, 9, 7, 13, 19, 23, 27, 20, 6, 17, 13, 10, 14, 6, 16, 15, 7, 2, 15, 15, 19, 70, 49, 7, 53, 22, 21, 31, 19, 11, 18, 20, 12, 35, 17, 23, 17, 4, 2, 31, 30, 13, 27, 0, 39, 37, 5, 14, 13, 22, ], dtype=tf.float32) n_count_data = tf.shape(count_data) days = tf.range(n_count_data[0],dtype=tf.int32) # Visualizing the Results plt.figure(figsize=(12.5, 4)) plt.bar(days.numpy(), count_data, color="#5DA5DA") plt.xlabel("Time (days)") plt.ylabel("count of text-msgs received") plt.title("Did the user's texting habits change over time?") plt.xlim(0, n_count_data[0].numpy()); def joint_log_prob(count_data, lambda_1, lambda_2, tau): tfd = tfp.distributions alpha = (1. / tf.reduce_mean(count_data)) rv_lambda_1 = tfd.Exponential(rate=alpha) rv_lambda_2 = tfd.Exponential(rate=alpha) rv_tau = tfd.Uniform() lambda_ = tf.gather( [lambda_1, lambda_2], indices=tf.cast(tau * tf.cast(tf.size(count_data), dtype=tf.float32) <= tf.cast(tf.range(tf.size(count_data)), dtype=tf.float32), dtype=tf.int32)) rv_observation = tfd.Poisson(rate=lambda_) return ( rv_lambda_1.log_prob(lambda_1) + rv_lambda_2.log_prob(lambda_2) + rv_tau.log_prob(tau) + tf.reduce_sum(rv_observation.log_prob(count_data)) ) # Define a closure over our joint_log_prob. def unnormalized_log_posterior(lambda1, lambda2, tau): return joint_log_prob(count_data, lambda1, lambda2, tau) # wrap the mcmc sampling call in a @tf.function to speed it up @tf.function(autograph=False) def graph_sample_chain(*args, **kwargs): return tfp.mcmc.sample_chain(*args, **kwargs) num_burnin_steps = 5000 num_results = 20000 # Set the chain's start state. initial_chain_state = [ tf.cast(tf.reduce_mean(count_data), tf.float32) * tf.ones([], dtype=tf.float32, name="init_lambda1"), tf.cast(tf.reduce_mean(count_data), tf.float32) * tf.ones([], dtype=tf.float32, name="init_lambda2"), 0.5 * tf.ones([], dtype=tf.float32, name="init_tau"), ] # Since HMC operates over unconstrained space, we need to transform the # samples so they live in real-space. unconstraining_bijectors = [ tfp.bijectors.Exp(), # Maps a positive real to R. tfp.bijectors.Exp(), # Maps a positive real to R. tfp.bijectors.Sigmoid(), # Maps [0,1] to R. ] step_size = 0.2 kernel=tfp.mcmc.TransformedTransitionKernel( inner_kernel=tfp.mcmc.HamiltonianMonteCarlo( target_log_prob_fn=unnormalized_log_posterior, num_leapfrog_steps=2, step_size=step_size, state_gradients_are_stopped=True), bijector=unconstraining_bijectors) kernel = tfp.mcmc.SimpleStepSizeAdaptation( inner_kernel=kernel, num_adaptation_steps=int(num_burnin_steps * 0.8)) # Sample from the chain. [ lambda_1_samples, lambda_2_samples, posterior_tau, ], kernel_results = graph_sample_chain( num_results=num_results, num_burnin_steps=num_burnin_steps, current_state=initial_chain_state, kernel = kernel) tau_samples = tf.floor(posterior_tau * tf.cast(tf.size(count_data),dtype=tf.float32)) print("acceptance rate: {}".format( tf.reduce_mean(tf.cast(kernel_results.inner_results.inner_results.is_accepted,dtype=tf.float32)))) print("final step size: {}".format( tf.reduce_mean(kernel_results.inner_results.inner_results.accepted_results.step_size[-100:]))) plt.figure(figsize=(12.5, 15)) #histogram of the samples: ax = plt.subplot(311) ax.set_autoscaley_on(False) plt.hist(lambda_1_samples, histtype='stepfilled', bins=30, alpha=0.85, label=r"posterior of $\lambda_1$", color=TFColor[0], density=True) plt.legend(loc="upper left") plt.title(r"""Posterior distributions of the variables $\lambda_1,\;\lambda_2,\;\tau$""") plt.xlim([15, 30]) plt.xlabel(r"$\lambda_1$ value") ax = plt.subplot(312) ax.set_autoscaley_on(False) plt.hist(lambda_2_samples, histtype='stepfilled', bins=30, alpha=0.85, label=r"posterior of $\lambda_2$", color=TFColor[6], density=True) plt.legend(loc="upper left") plt.xlim([15, 30]) plt.xlabel(r"$\lambda_2$ value") plt.subplot(313) w = 1.0 / tau_samples.shape[0] * np.ones_like(tau_samples) plt.hist(tau_samples, bins=n_count_data[0], alpha=1, label=r"posterior of $\tau$", color=TFColor[2], weights=w, rwidth=2.) plt.xticks(np.arange(n_count_data[0])) plt.legend(loc="upper left") plt.ylim([0, .75]) plt.xlim([35, len(count_data)-20]) plt.xlabel(r"$\tau$ (in days)") plt.ylabel(r"probability"); # tau_samples, lambda_1_samples, lambda_2_samples contain # N samples from the corresponding posterior distribution N_ = tau_samples.shape[0] expected_texts_per_day = tf.zeros(N_,n_count_data.shape[0]) #(10000,74) plt.figure(figsize=(12.5, 9)) day_range = tf.range(0,n_count_data[0],delta=1,dtype = tf.int32) # expand from shape of 74 to (10000,74) day_range = tf.expand_dims(day_range,0) day_range = tf.tile(day_range,tf.constant([N_,1])) # expand from shape of 10000 to 10000,74 tau_samples_per_day = tf.expand_dims(tau_samples,0) tau_samples_per_day = tf.transpose(tf.tile(tau_samples_per_day,tf.constant([day_range.shape[1],1]))) tau_samples_per_day = tf.cast(tau_samples_per_day,dtype=tf.int32) #ix_day is (10000,74) tensor where axis=0 is number of samples, axis=1 is day. each value is true iff sampleXday value is < tau_sample value ix_day = day_range < tau_samples_per_day lambda_1_samples_per_day = tf.expand_dims(lambda_1_samples,0) lambda_1_samples_per_day = tf.transpose(tf.tile(lambda_1_samples_per_day,tf.constant([day_range.shape[1],1]))) lambda_2_samples_per_day = tf.expand_dims(lambda_2_samples,0) lambda_2_samples_per_day = tf.transpose(tf.tile(lambda_2_samples_per_day,tf.constant([day_range.shape[1],1]))) expected_texts_per_day = ((tf.reduce_sum(lambda_1_samples_per_day*tf.cast(ix_day,dtype=tf.float32),axis=0) + tf.reduce_sum(lambda_2_samples_per_day*tf.cast(~ix_day,dtype=tf.float32),axis=0))/N_) plt.plot(range(n_count_data[0]), expected_texts_per_day, lw=4, color="#E24A33", label="expected number of text-messages received") plt.xlim(0, n_count_data.numpy()[0]) plt.xlabel("Day") plt.ylabel("Expected # text-messages") plt.title("Expected number of text-messages received") plt.ylim(0, 60) plt.bar(np.arange(len(count_data)), count_data, color="#5DA5DA", alpha=0.65, label="observed texts per day") plt.legend(loc="upper left"); #type your code here. #type your code here. #type your code here.