CodeBlanks Logo Icon CodeBlanks

Preparing data

Convert image data to tensors.

Project: horizontal and vertical lines

In this project we'll teach a small CNN to tell horizontal and vertical lines apart in 16×16 grey images. We generate the data ourselves: a thick line through the middle on a lightly noisy background. Class 0 is a horizontal line, class 1 a vertical one:

X = torch.rand(n, 1, 16, 16) * 0.3       # noisy background
# class 0: X[k, 0, 7:9, :] += 1  -> horizontal band
# class 1: X[k, 0, :, 7:9] += 1  -> vertical band

Synthetic data is a good way to quickly check that the code and the shapes are right before moving to a real image set.

Checking the data

Before training the data is checked: the shape, the class balance and whether an example really carries the expected pattern. For a horizontal line the mean of the middle rows is high; for a vertical one, that of the middle columns:

print(X_train.shape, torch.bincount(y_train).tolist())
k = (y_train == 0).nonzero()[0].item()           # first horizontal example
print(X_train[k, 0, 7:9].mean().item() > X_train[k, 0, :, 7:9].mean().item())

Because the classes are roughly balanced, accuracy is a meaningful metric here.

Practice Inspect the data

Print the shape of the training data. On one line print that for the first horizontal example the mean of the middle rows is larger than that of the middle columns, and the opposite for the first vertical example.

Starter code

model.py
import torch
from torch import nn

torch.manual_seed(0)
def veri(n):
    X = torch.rand(n, 1, 16, 16) * 0.3
    y = torch.randint(0, 2, (n,))
    for k in range(n):
        if y[k] == 0:
            X[k, 0, 7:9, :] += 1.0
        else:
            X[k, 0, :, 7:9] += 1.0
    return X, y

X_train, y_train = veri(256)
X_test, y_test = veri(64)

# buraya yaz

Sample solution

model.py
import torch
from torch import nn

torch.manual_seed(0)
def veri(n):
    X = torch.rand(n, 1, 16, 16) * 0.3
    y = torch.randint(0, 2, (n,))
    for k in range(n):
        if y[k] == 0:
            X[k, 0, 7:9, :] += 1.0
        else:
            X[k, 0, :, 7:9] += 1.0
    return X, y

X_train, y_train = veri(256)
X_test, y_test = veri(64)

print(X_train.shape)
k0 = (y_train == 0).nonzero()[0].item()
k1 = (y_train == 1).nonzero()[0].item()
a = X_train[k0, 0, 7:9].mean() > X_train[k0, 0, :, 7:9].mean()
b = X_train[k1, 0, :, 7:9].mean() > X_train[k1, 0, 7:9].mean()
print(a.item(), b.item())

Expected output

torch.Size([256, 1, 16, 16])
True True

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Why is the image tensor's shape (n, 1, 16, 16)?

  • It was chosen at random
  • For the linear layer
  • For an RNN
  • Conv2d wants (example, channel, height, width); a grey image has one channel Correct answer

Explanation: For a colour image the channel count would be 3.

2 Get the class counts.

Question
print(torch.____(y_train).tolist())
Answer
print(torch.bincount(y_train).tolist())

Explanation: torch.bincount counts non-negative integers.

3 Match the data pieces.

Term Meaning
torch.rand(...) * 0.3 Noisy background
X[k, 0, 7:9, :] Horizontal band
X[k, 0, :, 7:9] Vertical band
torch.randint(0, 2, (n,)) Random labels

All lessons in Advanced