@@ -275,6 +275,10 @@ def forward(self, x):
275275# * However, sampling `z` directly from `mu` and $std$(`logvar`) does not allow for backpropagation (random sampling is not differentiable)
276276# * To allow for backpropagation, we isolate the non-differentiable random sampling node and sample $\epsilon$ from a Normal distritubion with mean 0 and standard deviation 1
277277# * We then use this $\epsilon$ to produce `z`: `z` $=$ `mu` $+ \epsilon * e^{logvar/2}$ (here, gradient can flow through `mu` and `logvar`)
278+ #
279+ # 
280+ # Source: [Wikipedia](https://en.wikipedia.org/wiki/Reparameterization_trick#).
281+ #
278282#
279283# **The decode function**:
280284# * Takes in a latent vector `z` and uses an MLP to reconstruct the original sample, reshaping as appropriate.
@@ -509,8 +513,15 @@ def test_vae(w=28, h=28, latent_dim=16, batch_size=8):
509513# The reconstruction loss
510514rec_loss = nn .BCELoss (reduction = "sum" )
511515
516+ # %% [markdown]
517+ #
512518
513519# The KL loss
520+ # %% tags=["task"]
521+ def kl_loss (mu , logvar ):
522+ return ...
523+
524+ # %% tags=["solution"]
514525def kl_loss (mu , logvar ):
515526 # sum over latent dimensions, mean over batch
516527 return torch .mean (- 0.5 * torch .sum (1 + logvar - mu ** 2 - logvar .exp (), dim = 1 ))
@@ -689,7 +700,7 @@ def train_epochs(n, model, loader, optimizer, loss, beta, plot_every=10):
689700
690701# %%
691702epochs = 100
692- train_epochs (epochs , model , train_loader , optimizer , loss , beta = 1 );
703+ train_epochs (epochs , model , train_loader , optimizer , loss , beta = 1 )
693704
694705# %% [markdown]
695706# ### Part A.2.5: Inspect the trained model
@@ -789,7 +800,7 @@ def train_epochs(n, model, loader, optimizer, loss, beta, plot_every=10):
789800ax [2 ].set_title ("rec 2" )
790801plt .colorbar (im1 , shrink = 0.2 )
791802
792- im2 = ax [3 ].imshow (rec_1 - rec_2 , cmap = "Grays " )
803+ im2 = ax [3 ].imshow (rec_1 - rec_2 , cmap = "RdBu " )
793804ax [3 ].set_title ("rec 1 - rec 2" )
794805plt .colorbar (im2 , shrink = 0.2 )
795806
@@ -870,6 +881,8 @@ def view_test_sample(model, loader):
870881
871882# %% [markdown]
872883# <div class="alert alert-block alert-info"><h2>Task</h2>
884+ # We will now train two models, `model0` without regularization and `model1` with regularization.
885+ # To acheive this, we set the `beta` parameter for the loss used with `model0` to `0`.
873886#
874887# Let's train our first "serious" model.
875888# * Instantiate a new variational autoencoder model and name it `model0`
@@ -945,12 +958,10 @@ def view_test_sample(model, loader):
945958model1 = VariationalAutoEncoder (w , h , latent_dim = 2 ).to (device )
946959optimizer = Adam (model1 .parameters (), lr = 0.0001 ) # fresh optimizer
947960epochs = 1000
948- beta = 0
961+ beta = # TODO
949962losses1 = train_epochs (epochs , model1 , train_loader , optimizer , loss , beta = beta )
950963
951964
952-
953-
954965# %% tags=["solution"]
955966# beta 1
956967model1 = VariationalAutoEncoder (w , h , latent_dim = 2 ).to (device )
@@ -1089,12 +1100,8 @@ def scatter_digits(ax, mus, lbls, mu_mean=None, alpha=1, CMAP = "tab10"):
10891100
10901101 if mu_mean is not None :
10911102 for d in range (10 ):
1092- ax .scatter (* mu_mean [d ], s = 220 , color = "white" , edgecolors = "white" , linewidths = 3 , marker = "X" , zorder = 9 )
1093- ax .scatter (* mu_mean [d ], s = 80 , color = CMAP (d ), edgecolors = "black" , linewidths = 0.5 , marker = "X" , zorder = 10 )
1094- ax .annotate (str (d ), xy = mu_mean [d ], fontsize = 8 , fontweight = "bold" ,
1095- ha = "center" , va = "bottom" , xytext = (0 , 5 ),
1096- textcoords = "offset points" , zorder = 11 ,
1097- bbox = dict (boxstyle = "round,pad=0.15" , fc = "white" , ec = "none" , alpha = 0.8 ))
1103+ ax .scatter (* mu_mean [d ], s = 100 , color = "white" , edgecolors = "white" , linewidths = 0.4 , marker = "X" , zorder = 9 )
1104+ ax .scatter (* mu_mean [d ], s = 70 , color = CMAP (d ), edgecolors = "black" , linewidths = 0.5 , marker = "X" , zorder = 10 )
10981105
10991106 ax .legend (title = "Digit" , markerscale = 6 , ncol = 2 , fontsize = 7 , loc = "best" )
11001107 ax .set_aspect ("equal" )
@@ -1110,14 +1117,14 @@ def scatter_with_normal(ax, mus, lbls, rnd_normal, mean, std):
11101117 ax .set_aspect ("equal" )
11111118
11121119
1113- def plot_latent_digits (mus_model0 , lbls0 , mu_mean0 , mus_model1 , lbls1 , mu_mean1 ):
1120+ def plot_latent_digits (mus_model0 , lbls0 , mu_mean0 , mus_model1 , lbls1 , mu_mean1 , alpha = 1 , CMAP = "tab10" ):
11141121 """Latent space coloured by digit, with per-class centroids."""
11151122 fig , axes = plt .subplots (1 , 2 , figsize = (13 , 5 ))
11161123 for ax , mus , lbls , mu_mean , title in [
11171124 (axes [0 ], mus_model0 , lbls0 , mu_mean0 , "model0: β=0 latent space" ),
11181125 (axes [1 ], mus_model1 , lbls1 , mu_mean1 , "model1: β>0 latent space" ),
11191126 ]:
1120- scatter_digits (ax , mus , lbls , mu_mean = mu_mean )
1127+ scatter_digits (ax , mus , lbls , mu_mean = mu_mean , alpha = alpha , CMAP = CMAP )
11211128 ax .set_title (title , fontsize = 11 )
11221129 ax .set_xlabel ("mu₁" ); ax .set_ylabel ("mu₂" )
11231130 fig .suptitle ("Latent space — coloured by digit" , fontsize = 13 )
@@ -1203,7 +1210,7 @@ def plot_latent_vs_normal(mus_model0, lbls0, mus_model1, lbls1, rnd_normal,
12031210#
12041211# Below we will sample 100 values `z` from `mu` and `logvar`.
12051212#
1206- # So each of the 10000 test-image is represented by 100 points – 100000 points in total.
1213+ # So each of the 10000 test-image is represented by 100 points – 1000000 points in total.
12071214
12081215# %%
12091216def sample_from_latents (mus , logvars , n_samples = 100 ):
@@ -1340,7 +1347,7 @@ def plot_decision_boundaries(ax, clf, mus, lbls, title, resolution=500, CMAP="ta
13401347
13411348 # Draw crisp decision boundaries
13421349 ax .contour (xx , yy , grid_preds , levels = np .arange (- 0.5 , 10 , 1 ),
1343- colors = "k" , linewidths = 0.4 , zorder = 1 )
1350+ colors = "k" , linewidths = 0.4 , zorder = 10 )
13441351
13451352 # Overlay data points
13461353 scatter_digits (ax , mus , lbls )
@@ -1444,6 +1451,11 @@ def gen_mean_numbers(model, mu_mean, title):
14441451# We can decode points sampled along the straight line between two centroids in latent space. A visualization will be plotted below.
14451452#
14461453
1454+ # %% [markdown]
1455+ # <div class="alert alert-block alert-warning"><h3>Questions</h3>
1456+ # Can we interpolate and reconstruct the same way with different architectures? (AE, ResNet, UNet, etc...)
1457+ # </div>
1458+
14471459# %% [markdown]
14481460# <div class="alert alert-block alert-info"><h2>Task</h2>
14491461# Run the code below without modifications. You should see reconstructions of interpolated images along the path between the centroids of 0 and 6. <br>
@@ -1656,28 +1668,11 @@ def run_umap(latents, n_components=2, random_state=42, n_neighbors=15, min_dist=
16561668 return mu_2d
16571669
16581670
1659- def plot_umap (mu_2d , labels ,
1660- cmap = 'tab10' , alpha = 0.6 , s = 10 , centers = None , center_labels = None ):
1661-
1662- ticks = np .unique (labels )
1663- base_cmap = plt .get_cmap (cmap )
1664- colors_n = base_cmap (np .linspace (0 , 1 , np .max (ticks ) + 1 ))
1665- new_cmap = ListedColormap (colors_n )
1666-
1667- plt .figure (figsize = (10 , 8 ))
1668- scatter = plt .scatter (mu_2d [:, 0 ], mu_2d [:, 1 ], c = labels , cmap = new_cmap , alpha = alpha , s = s )
1669- plt .colorbar (scatter , ticks = ticks )
1670-
1671- if centers is not None :
1672- for i , label in enumerate (center_labels ):
1673- plt .text (centers [i , 0 ], centers [i , 1 ], s = str (label ), backgroundcolor = "white" , size = 'large' )
1674- plt .scatter (centers [:, 0 ], centers [:, 1 ], s = 50 , marker = "X" , c = "k" , zorder = 10000 )
1675- plt .axis ('off' )
1676-
16771671
16781672# %%
16791673mu_2d_2 , mu_means_2d_2 = run_umap (mus2 , means = mu_mean2 )
1680- plot_umap (mu_2d_2 , lbls2 , cmap = "tab10" , centers = mu_means_2d_2 , center_labels = range (10 ))
1674+ _ , ax = plt .subplots (1 , 1 , figsize = (10 , 8 ))
1675+ scatter_digits (ax , mu_2d_2 , lbls2 , mu_means_2d_2 , alpha = 0.6 )
16811676
16821677# %% [markdown]
16831678# Clusters look well-separated, but we should verify with logistic regression.
0 commit comments