import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import seaborn as sns
import tensorflow_probability as tfp
import pandas as pd
= tfp.distributions
tfd
sns.reset_defaults()='talk',font_scale=1)
sns.set_context(context%matplotlib inline
%config InlineBackend.figure_format='retina'
Univariate normal
= tfd.Normal(loc=0., scale=1.) uv_normal
uv_normal
<tfp.distributions.Normal 'Normal' batch_shape=[] event_shape=[] dtype=float32>
= uv_normal.sample(1000) samples
sns.histplot(samples.numpy()) sns.despine()
='kde') sns.displot(samples.numpy(), kind
= {x: tfd.Normal(loc=x, scale=1.) for x in [-2, -1, 0, 1, 2]} uv_normal_dict_mean
= pd.DataFrame({x:uv_normal_dict_mean[x].sample(10000).numpy()
uv_normal_dict_mean_samples for x in uv_normal_dict_mean})
='kde', fill=True) sns.displot(uv_normal_dict_mean_samples, kind
= {x: tfd.Normal(loc=0, scale=x) for x in [1, 2, 5, 10]}
uv_normal_dict_var = pd.DataFrame({x:uv_normal_dict_var[x].sample(10000).numpy()
uv_normal_dict_var_samples for x in uv_normal_dict_var})
='kde', fill=True) sns.displot(uv_normal_dict_var_samples, kind
Using batches
= pd.DataFrame(
var_dfs =[0., 0., 0., 0.],
tfd.Normal(loc=[1., 2., 5., 10.]).sample(10000).numpy())
scale= [1, 2, 5, 10]
var_dfs.columns ='kde', fill=True) sns.displot(var_dfs, kind
=[0., 0., 0., 0.],
tfd.Normal(loc=[1., 2., 5., 10.]) scale
<tfp.distributions.Normal 'Normal' batch_shape=[4] event_shape=[] dtype=float32>
= uv_normal.sample(10000)
samples ='kde')
sns.displot(samples.numpy(), kind0.5, color='k', linestyle='--')
plt.axvline(= uv_normal.prob(0.5).numpy()
pdf_05 = uv_normal.log_prob(0.5).numpy()
log_pdf_05
"Density at x = 0.5 is {:.2f}\n Logprob at x = 0.5 is {:.2f}".format(pdf_05, log_pdf_05)) plt.title(
Text(0.5, 1.0, 'Density at x = 0.5 is 0.35\n Logprob at x = 0.5 is -1.04')
Learning parameters
Let us generate some normally distributed data and see if we can learn
the mean.
= uv_normal.sample(10000) train_data
uv_normal.loc, uv_normal.scale
(<tf.Tensor: shape=(), dtype=float32, numpy=0.0>,
<tf.Tensor: shape=(), dtype=float32, numpy=1.0>)
Let us create a new TFP trainable distribution where we wish to learn the mean.
= tfd.Normal(loc = tf.Variable(-1., name='loc'), scale = 1.) to_train
to_train
<tfp.distributions.Normal 'Normal' batch_shape=[] event_shape=[] dtype=float32>
to_train.trainable_variables
(<tf.Variable 'loc:0' shape=() dtype=float32, numpy=-1.0>,)
tf.reduce_mean(train_data), tf.math.reduce_variance(train_data)
(<tf.Tensor: shape=(), dtype=float32, numpy=-0.024403999>,
<tf.Tensor: shape=(), dtype=float32, numpy=0.9995617>)
def nll(train):
return -tf.reduce_mean(to_train.log_prob(train))
nll(train_data)
<tf.Tensor: shape=(), dtype=float32, numpy=1.8946133>
def get_loss_and_grads(train):
with tf.GradientTape() as tape:
tape.watch(to_train.trainable_variables)= nll(train)
loss = tape.gradient(loss, to_train.trainable_variables)
grads return loss, grads
get_loss_and_grads(train_data)
(<tf.Tensor: shape=(), dtype=float32, numpy=1.8946133>,
(<tf.Tensor: shape=(), dtype=float32, numpy=-0.97559595>,))
= tf.keras.optimizers.Adam(learning_rate=0.01) optimizer
optimizer
<keras.optimizer_v2.adam.Adam at 0x7f94c97ae490>
= 500
iterations = np.empty(iterations)
losses = np.empty(iterations)
vals for i in range(iterations):
= get_loss_and_grads(train_data)
loss, grads = loss
losses[i] = to_train.trainable_variables[0].numpy()
vals[i] zip(grads, to_train.trainable_variables))
optimizer.apply_gradients(if i%50 == 0:
print(i, loss.numpy())
0 1.8946133
50 1.5505791
100 1.4401271
150 1.4205703
200 1.4187955
250 1.4187206
300 1.4187194
350 1.4187193
400 1.4187193
450 1.4187194
plt.plot(losses)
sns.despine()"Iterations")
plt.xlabel("Loss") plt.ylabel(
Text(0, 0.5, 'Loss')
plt.plot(vals)
sns.despine()"Iterations")
plt.xlabel(r"Value of $\hat{\mu}$") plt.ylabel(
Text(0, 0.5, 'Value of $\\hat{\\mu}$')
= tfd.Normal(loc = tf.Variable(-1., name='loc'), scale = tf.Variable(10., name='scale'))
to_train_mean_var
def nll(train):
return -tf.reduce_mean(to_train_mean_var.log_prob(train))
def get_loss_and_grads(train):
with tf.GradientTape() as tape:
tape.watch(to_train_mean_var.trainable_variables)= nll(train)
loss = tape.gradient(loss, to_train_mean_var.trainable_variables)
grads return loss, grads
to_train_mean_var.trainable_variables
= tf.keras.optimizers.Adam(learning_rate=0.01)
optimizer
= 1000
iterations = np.empty(iterations)
losses = np.empty(iterations)
vals_scale = np.empty(iterations)
vals_means for i in range(iterations):
= get_loss_and_grads(train_data)
loss, grads = loss
losses[i] = to_train_mean_var.trainable_variables[0].numpy()
vals_means[i] = to_train_mean_var.trainable_variables[1].numpy()
vals_scale[i]
zip(grads, to_train_mean_var.trainable_variables))
optimizer.apply_gradients(if i%50 == 0:
print(i, loss.numpy())
0 3.2312806
50 3.1768403
100 3.1204312
150 3.0602157
200 2.9945102
250 2.9219644
300 2.8410006
350 2.749461
400 2.6442661
450 2.5208094
500 2.3718355
550 2.1852348
600 1.9403238
650 1.6161448
700 1.4188237
750 1.4187355
800 1.4187193
850 1.4187193
900 1.4187193
950 1.4187193
plt.plot(losses)
sns.despine()"Iterations")
plt.xlabel("Loss") plt.ylabel(
Text(0, 0.5, 'Loss')
= pd.DataFrame({"Mean":vals_means, "Scale":vals_scale}, index=range(iterations))
df = 'Iteration' df.index.name
=1)
df.plot(alpha
sns.despine()0, linestyle='--', lw = 4, label = 'True mean', alpha=0.5, color='purple')
plt.axhline(1, linestyle='--', lw = 4, label = 'True scale', alpha=0.5, color='red')
plt.axhline( plt.legend()
Multivariate Normal
= tfd.MultivariateNormalFullCovariance(loc=[0, 0], covariance_matrix=[[1, 0.5], [0.5, 2]]) mv_normal
= pd.DataFrame(mv_normal.sample(10000).numpy())
mv_data = [r'$x_1$', r'$x_2$'] mv_data.columns
0, 0]) mv_normal.prob([
<tf.Tensor: shape=(), dtype=float32, numpy=0.120309845>
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
def make_pdf_2d_gaussian(mu, sigma):
= 60
N = np.linspace(-3, 3, N)
X = np.linspace(-3, 4, N)
Y = np.meshgrid(X, Y)
X, Y
# Pack X and Y into a single 3-dimensional array
= np.empty(X.shape + (2,))
pos 0] = X
pos[:, :, 1] = Y
pos[:, :,
= tfd.MultivariateNormalFullCovariance(loc=mu, covariance_matrix=sigma)
F = F.prob(pos)
Z
=cm.Purples)
plt.contourf(X, Y, Z, cmap
sns.despine() r"$x_1$")
plt.xlabel(r"$x_2$")
plt.ylabel('equal')
plt.gca().set_aspect(f'$\mu$ = {mu}\n $\Sigma$ = {np.array(sigma)}') plt.title(
0, 0,], [[1, 0.5,], [0.5, 1]]) make_pdf_2d_gaussian([
0, 0,], [[3, 0.,], [0., 1]]) make_pdf_2d_gaussian([
=mv_data,
sns.jointplot(data=r'$x_1$',y=r'$x_2$',
x=0.1) alpha
mv_data
$x_1$ | $x_2$ | |
---|---|---|
0 | 2.155621 | -0.343866 |
1 | -0.731184 | 0.378393 |
2 | 0.832593 | -0.459740 |
3 | -0.701200 | -0.249675 |
4 | -0.430790 | -1.694002 |
... | ... | ... |
9995 | -0.165910 | -0.171243 |
9996 | 0.208389 | -1.698432 |
9997 | -0.030418 | 0.353905 |
9998 | 1.342328 | 1.127457 |
9999 | -0.145741 | 0.830713 |
10000 rows × 2 columns