Hi everyone,
I wanted to share a visualization routine I put together while working through this section. It plots the letter images sentence by sentence, which I found helpful for visually checking what the model predicted and that everything worked correctly.
One thing I ran into: since the subplots are squares, adjusting hspace to add vertical space between sentences also increases the horizontal spacing between letters. To work around this, I used height_ratios in GridSpec to insert explicit gap rows between sentences — that way the two spacings can be controlled independently.
import matplotlib.pyplot as plt
from functools import reduce
# We will create a single subplot for each letter image, so we need to calculate max width.
# Sum of word lengths + (number of words - 1) for spaces
max_num_letters_in_sentence = max(
sum(len(word) for word in sentence) + len(sentence) - 1
for sentence in message_imgs
)
n_sentences = len(message_imgs)
fig_width = 15
letter_height = 1
gap_height = 0.75
# Create an array of alternating height ratios.
# By introducing a gap height, the gap between sentences can be readily adjusted.
# (Because the subplots are squares, trying to create a vertical gap by setting
# the `hspace` parameter instead will also increase the horizontal space between letters.)
height_ratios = []
for i in range(n_sentences):
height_ratios.append(letter_height)
if i < n_sentences - 1:
height_ratios.append(gap_height)
n_rows = len(height_ratios)
fig = plt.figure()
gs = fig.add_gridspec(n_rows, max_num_letters_in_sentence, height_ratios=height_ratios, hspace=0, wspace=0)
for sentence_idx, sentence_list in enumerate(message_imgs):
# Combine the individual words of a sentence into a single list
# with None (space) between them to facilitate iteration.
full_sentence_imgs = reduce(lambda w1, w2: w1 + [None] + w2, sentence_list)
row_idx = sentence_idx * 2
for letter_index, letter_img in enumerate(full_sentence_imgs):
if letter_img is not None:
img_transformed = correct_image_orientation(letter_img)
img = img_transformed.numpy().squeeze()
ax = fig.add_subplot(gs[row_idx, letter_index])
ax.set_box_aspect(1)
ax.imshow(img, cmap="gray_r", vmin=0, vmax=1, aspect='equal')
ax.axis('off')
plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01)
total_height_in_units_of_letters = sum(height_ratios)
# Set the width and height of the figure so that it matches
# the number of rows and the number of letters per row.
fig.set_size_inches(fig_width, fig_width * (total_height_in_units_of_letters / max_num_letters_in_sentence))
plt.show()
Hope someone finds it useful — happy to hear if you have suggestions for improvement!
Copy and pasting should work (I added the routine below the code cell after “You are finally ready to decode the secret message!”), but maybe this routine could also be used to inspire a helper routine in future iterations of the notebook.
Best regards,
Carl