Task: trace and explain the dimensionality of each tensor in a simple image classifier.
from fastai.vision.all import *
from fastbook import *
matplotlib.rc('image', cmap='Greys')
Get some example digits from the MNIST dataset.
path = untar_data(URLs.MNIST_SAMPLE)
threes = (path/'train'/'3').ls().sorted()
sevens = (path/'train'/'7').ls().sorted()
len(threes), len(sevens)
Here is one image:
example_3 = Image.open(threes[1])
example_3
To prepare to use it as input to a neural net, we first convert integers from 0 to 255 into floating point numbers between 0 and 1.
example_3_tensor = tensor(example_3).float() / 255
example_3_tensor.shape
height, width = example_3_tensor.shape
Our particular network will ignore the spatial relationship between the features; later we'll learn about network architectures that do pay attention to spatial neighbors. So we'll flatten the image tensor into 28*28 values.
example_3_flat = example_3_tensor.view(width * height)
example_3_flat.shape
We'll define a simple neural network (in the book, a 3-vs-7 classifier) as the sequential combination of 3 layers. First we define each layer:
# Define the layers. This is where you'll try changing constants.
linear_1 = nn.Linear(in_features=784, out_features=30)
relu_layer = nn.ReLU()
linear_2 = nn.Linear(in_features=30, out_features=1)
Then we put them together in sequence.
simple_net = nn.Sequential(
linear_1,
relu_layer,
linear_2
)
Each of nn.Linear, nn.ReLU, and nn.Squential are PyTorch modules. We can call a module with some input data to get the output data:
simple_net(example_3_flat)
Your turn:
The outputs of each layer are called activations, so we can name the variables act1 for the activations of layer 1, and so forth. Each act will be a function of the previous act (or the input, for the first layer.)
inp = example_3_flat
act1 = ...
act2 = ...
act3 = ...
act1, act2, and act3. (Code already provided; look at the results.)act1
act2
act3
shape of act1, act2, and act3.# your code here
linear_1.in_features, linear_2.out_features, etc. (ignore the torch.Size( part)linear_1.in_features
act1_shape = [...]
act2_shape = [...]
act3_shape = [...]
assert list(act1_shape) == list(act1.shape)
assert list(act2_shape) == list(act2.shape)
assert list(act3_shape) == list(act3.shape)
shape of linear_1.weight, linear_1.bias, and the same for linear_2. Write expressions that give the value of each shape in terms of the in_features and other parameters.print(f"Linear 1: Weight shape is {list(linear_1.weight.shape)}, bias shape is {list(linear_1.bias.shape)}")
print(f"Linear 2: Weight shape is {list(linear_2.weight.shape)}, bias shape is {list(linear_2.bias.shape)}")
linear_1_weight_shape = [...]
linear_1_bias_shape = [...]
linear_2_weight_shape = [...]
linear_2_bias_shape = [...]
assert list(linear_1_weight_shape) == list(linear_1.weight.shape)
assert list(linear_1_bias_shape) == list(linear_1.bias.shape)
assert list(linear_2_weight_shape) == list(linear_2.weight.shape)
assert list(linear_2_bias_shape) == list(linear_2.bias.shape)
nn.Linear modules. Identify an example of:your answer here
act1 and act2.your answer here
Linear layer (weight and bias).your answer here