Preparing data
- Machine Learning course
- Advanced
- Lesson 59/78
- 7 min
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 bandSynthetic 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
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 yazSample solution
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.
print(torch.____(y_train).tolist())
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 |