Jovian
⭐️
Sign In

Expolring the data

In [1]:
import torch
import torchvision # conftaining utilities to work with image data.
from torchvision.datasets import MNIST
In [2]:
# Download the training data
dataset = MNIST(root = 'data/', download = 'True')
In [3]:
MNIST
Out[3]:
torchvision.datasets.mnist.MNIST
In [4]:
len(dataset)
Out[4]:
60000
In [5]:
type(dataset)
Out[5]:
torchvision.datasets.mnist.MNIST
In [6]:
test_dataset = MNIST(root = 'data/', train = False)
In [7]:
len(test_dataset)
Out[7]:
10000
In [8]:
dataset[0]
Out[8]:
(<PIL.Image.Image image mode=L size=28x28 at 0x128F7D410>, 5)
In [9]:
!pip install matplotlib
Requirement already satisfied: matplotlib in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (3.1.2) Requirement already satisfied: numpy>=1.11 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from matplotlib) (1.17.4) Requirement already satisfied: python-dateutil>=2.1 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from matplotlib) (2.8.1) Requirement already satisfied: cycler>=0.10 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from matplotlib) (0.10.0) Requirement already satisfied: kiwisolver>=1.0.1 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from matplotlib) (1.1.0) Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from matplotlib) (2.4.5) Requirement already satisfied: six>=1.5 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from python-dateutil>=2.1->matplotlib) (1.13.0) Requirement already satisfied: setuptools in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib) (41.6.0.post20191030)
In [10]:
import matplotlib.pyplot as plt
In [11]:
# magic command to let the plots appear embedded in the notebook rather than as popups.
%matplotlib inline 
In [12]:
image, label = dataset[10]
In [13]:
plt.imshow(image, cmap = 'gray')
print('Label: ', label)
Label: 3
Notebook Image
In [14]:
type(image)
Out[14]:
PIL.Image.Image
In [15]:
type(label)
Out[15]:
int
In [16]:
from torchvision.transforms import transforms
In [17]:
# Recreate the dataset objects with images transformed into tensors.
dataset = MNIST('data/', train = True, transform = transforms.ToTensor())
In [18]:
img_tensor, label = dataset[0]
In [19]:
print(img_tensor.shape, label)
torch.Size([1, 28, 28]) 5
In [20]:
print(img_tensor[:, 10:15, 10:15])
tensor([[[0.0039, 0.6039, 0.9922, 0.3529, 0.0000], [0.0000, 0.5451, 0.9922, 0.7451, 0.0078], [0.0000, 0.0431, 0.7451, 0.9922, 0.2745], [0.0000, 0.0000, 0.1373, 0.9451, 0.8824], [0.0000, 0.0000, 0.0000, 0.3176, 0.9412]]])
In [21]:
print(torch.max(img_tensor), torch.min(img_tensor))
tensor(1.) tensor(0.)
In [22]:
plt.imshow(img_tensor[0, 10:15, 10:15], cmap = 'gray')
Out[22]:
<matplotlib.image.AxesImage at 0x12e0b7610>
Notebook Image

Training and Validation Datasets

In [23]:
import numpy as np
In [24]:
def split_indices(n, val_pct):
    # Determine size of validation set.
    n_val = int(val_pct * n)
    # Create random permutation from 0 to n-1
    idxs = np.random.permutation(n)
    # Pick first n_val indices for validation set.
    return idxs[n_val:], idxs[:n_val]
In [25]:
train_indices, val_indices = split_indices(len(dataset), val_pct = 0.2)
In [26]:
val_indices
Out[26]:
array([29388, 14239, 24892, ..., 21294, 33683,   550])
In [27]:
print(len(train_indices), len(val_indices))
48000 12000
In [28]:
print('Sample validation indices', val_indices[:20])
Sample validation indices [29388 14239 24892 48269 18354 37750 46357 2272 7044 15702 13106 14840 17858 58979 28088 11135 51645 256 15062 25805]
In [29]:
from torch.utils.data.sampler import SubsetRandomSampler
from torch.utils.data.dataloader import DataLoader
In [172]:
batch_size = 200

# Training sampler and data loader.
train_sampler = SubsetRandomSampler(train_indices)
train_loader = DataLoader(dataset, batch_size, sampler = train_sampler)

# Validation sampler and data loader
val_sampler = SubsetRandomSampler(val_indices)
val_loader = DataLoader(dataset, batch_size, sampler = val_sampler)
In [173]:
train_sampler
Out[173]:
<torch.utils.data.sampler.SubsetRandomSampler at 0x133aa0b10>

Save and commit the notebook

In [174]:
import jovian
In [175]:
jovian.commit()
[jovian] Saving notebook..
[jovian] Updating notebook "2bb6249741384832bcc18ab47036e211" on https://jovian.ml/ [jovian] Uploading notebook.. [jovian] Capturing environment.. [jovian] Recording metrics & hyperparameters.. [jovian] Committed successfully! https://jovian.ml/walid-gomaa/image-classification

Creating the model

In [176]:
import torch.nn as nn

input_size = 28 * 28
num_classes = 10

# Logistic regression model.
model = nn.Linear(input_size, num_classes)
In [177]:
print(model.weight.shape)
torch.Size([10, 784])
In [178]:
model.weight
Out[178]:
Parameter containing:
tensor([[ 0.0228,  0.0211,  0.0251,  ..., -0.0184,  0.0241,  0.0003],
        [ 0.0345,  0.0116,  0.0212,  ...,  0.0195, -0.0016, -0.0217],
        [ 0.0313, -0.0257, -0.0020,  ..., -0.0284, -0.0245, -0.0178],
        ...,
        [-0.0300,  0.0023, -0.0268,  ..., -0.0045, -0.0278,  0.0232],
        [-0.0200,  0.0205,  0.0241,  ...,  0.0046,  0.0306,  0.0009],
        [ 0.0130,  0.0325, -0.0289,  ...,  0.0010,  0.0312,  0.0343]],
       requires_grad=True)
In [179]:
model.bias
Out[179]:
Parameter containing:
tensor([-0.0017,  0.0313,  0.0124, -0.0081, -0.0133,  0.0294,  0.0208,  0.0003,
         0.0356, -0.0017], requires_grad=True)
In [181]:
for images, labels in train_loader:
    print(labels)
    print(images.shape)
    outputs = model(images)
    break
tensor([6, 7, 9, 5, 0, 5, 1, 4, 4, 1, 1, 0, 4, 7, 8, 5, 3, 0, 6, 9, 9, 4, 4, 1, 0, 8, 6, 1, 8, 2, 9, 2, 0, 5, 2, 4, 2, 9, 4, 6, 3, 4, 4, 9, 1, 7, 9, 4, 9, 4, 8, 4, 6, 2, 9, 4, 1, 9, 5, 5, 8, 6, 7, 3, 9, 0, 3, 2, 0, 1, 4, 7, 2, 4, 2, 1, 5, 7, 6, 7, 5, 1, 2, 8, 3, 8, 6, 8, 7, 0, 0, 9, 7, 4, 6, 3, 5, 2, 1, 3, 5, 6, 7, 1, 8, 9, 4, 9, 6, 0, 4, 6, 1, 9, 8, 9, 7, 2, 8, 0, 7, 5, 9, 6, 2, 7, 7, 9, 8, 5, 8, 4, 9, 2, 2, 2, 8, 5, 5, 2, 5, 9, 2, 0, 9, 3, 9, 3, 3, 2, 0, 0, 0, 0, 3, 0, 8, 3, 6, 3, 1, 9, 0, 3, 6, 0, 9, 5, 1, 1, 9, 8, 4, 3, 4, 1, 0, 2, 8, 7, 1, 9, 5, 4, 3, 9, 7, 7, 0, 7, 4, 7, 8, 1, 5, 1, 0, 6, 6, 6]) torch.Size([200, 1, 28, 28])
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-181-72eddc737460> in <module> 2 print(labels) 3 print(images.shape) ----> 4 outputs = model(images) 5 break /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages/torch/nn/modules/module.py in __call__(self, *input, **kwargs) 539 result = self._slow_forward(*input, **kwargs) 540 else: --> 541 result = self.forward(*input, **kwargs) 542 for hook in self._forward_hooks.values(): 543 hook_result = hook(self, input, result) /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages/torch/nn/modules/linear.py in forward(self, input) 85 86 def forward(self, input): ---> 87 return F.linear(input, self.weight, self.bias) 88 89 def extra_repr(self): /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages/torch/nn/functional.py in linear(input, weight, bias) 1370 ret = torch.addmm(bias, input, weight.t()) 1371 else: -> 1372 output = input.matmul(weight.t()) 1373 if bias is not None: 1374 output += bias RuntimeError: size mismatch, m1: [5600 x 28], m2: [784 x 10] at ../aten/src/TH/generic/THTensorMath.cpp:197
In [182]:
class MnistModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(input_size, num_classes)
        
    def forward(self, xb):
        xb = xb.reshape(-1, 784)
        out = self.linear(xb)
        return out
In [183]:
model = MnistModel()
In [184]:
print(model.linear.weight.shape, model.linear.bias.shape)
torch.Size([10, 784]) torch.Size([10])
In [185]:
list(model.parameters())
Out[185]:
[Parameter containing:
 tensor([[-0.0077, -0.0161, -0.0221,  ...,  0.0177, -0.0064, -0.0333],
         [-0.0128, -0.0068,  0.0268,  ...,  0.0198, -0.0150,  0.0207],
         [ 0.0038,  0.0256, -0.0157,  ..., -0.0113, -0.0342, -0.0014],
         ...,
         [ 0.0332,  0.0215,  0.0102,  ..., -0.0305, -0.0236, -0.0301],
         [ 0.0141,  0.0042,  0.0126,  ..., -0.0045,  0.0213, -0.0047],
         [-0.0082, -0.0107, -0.0087,  ...,  0.0209, -0.0239,  0.0296]],
        requires_grad=True), Parameter containing:
 tensor([ 0.0187, -0.0118,  0.0332,  0.0029, -0.0166, -0.0144,  0.0108, -0.0300,
         -0.0320, -0.0133], requires_grad=True)]
In [186]:
for images, labels in train_loader:
    outputs = model(images)
    break
In [187]:
type(outputs)
Out[187]:
torch.Tensor
In [188]:
print("Outputs.shape : ", outputs.shape)
print("Sample outputs : \n", outputs[:2].data)
Outputs.shape : torch.Size([200, 10]) Sample outputs : tensor([[-0.0916, 0.1190, 0.3846, -0.2106, 0.0045, 0.1950, 0.3499, -0.0475, -0.4263, -0.2584], [ 0.0108, -0.1688, 0.1136, -0.3499, 0.0588, 0.1138, -0.1544, -0.1791, -0.4214, -0.0539]])
In [189]:
import torch.nn.functional as F
In [190]:
# Apply softmax for each output row.
probs = F.softmax(outputs, dim = 1)
In [191]:
type(probs)
Out[191]:
torch.Tensor
In [192]:
# Look at sample probabilities.
print("Sample probabilities:\n", probs[:2].data)
Sample probabilities: tensor([[0.0883, 0.1090, 0.1421, 0.0784, 0.0972, 0.1176, 0.1373, 0.0923, 0.0632, 0.0747], [0.1104, 0.0922, 0.1223, 0.0770, 0.1158, 0.1224, 0.0936, 0.0913, 0.0716, 0.1035]])
In [193]:
# Add up the probabilities of an output row.
print("Sum: ", torch.sum(probs[0]).item())
Sum: 1.0
In [194]:
max_probs, preds = torch.max(probs, dim = 1)
In [195]:
type(probs)
Out[195]:
torch.Tensor
In [196]:
probs.shape
Out[196]:
torch.Size([200, 10])
In [197]:
print(preds)
print(max_probs)
tensor([2, 5, 0, 6, 4, 9, 6, 5, 6, 4, 4, 2, 6, 2, 0, 4, 6, 4, 4, 5, 6, 0, 6, 4, 4, 2, 6, 2, 4, 0, 4, 2, 4, 4, 4, 6, 2, 2, 2, 4, 4, 4, 4, 4, 6, 2, 6, 2, 0, 6, 6, 6, 2, 1, 5, 9, 6, 4, 5, 4, 2, 2, 0, 4, 4, 6, 5, 9, 1, 2, 2, 2, 2, 2, 4, 2, 6, 2, 5, 0, 0, 6, 6, 0, 4, 2, 4, 9, 4, 6, 4, 5, 4, 9, 4, 4, 2, 2, 6, 4, 6, 6, 4, 2, 6, 2, 9, 0, 6, 9, 1, 6, 4, 2, 5, 0, 4, 4, 4, 6, 4, 5, 5, 4, 0, 2, 4, 2, 4, 6, 4, 4, 4, 6, 6, 6, 6, 4, 6, 2, 6, 2, 6, 5, 2, 2, 9, 6, 2, 9, 6, 6, 4, 4, 6, 5, 4, 2, 2, 2, 2, 6, 4, 6, 5, 4, 0, 0, 4, 2, 4, 6, 6, 9, 4, 2, 6, 9, 2, 5, 4, 0, 6, 6, 0, 2, 4, 6, 4, 6, 5, 4, 4, 6, 4, 4, 2, 9, 0, 4]) tensor([0.1421, 0.1224, 0.1244, 0.1209, 0.1217, 0.1346, 0.1853, 0.1180, 0.1295, 0.1278, 0.1304, 0.1461, 0.1348, 0.2150, 0.1284, 0.1299, 0.1813, 0.1375, 0.1408, 0.1416, 0.1398, 0.1227, 0.1376, 0.1508, 0.1561, 0.1245, 0.1328, 0.1381, 0.1281, 0.1353, 0.1366, 0.1430, 0.1381, 0.1355, 0.1526, 0.1219, 0.1409, 0.1373, 0.1365, 0.1456, 0.1350, 0.1402, 0.1247, 0.1411, 0.1357, 0.1636, 0.1535, 0.1743, 0.1357, 0.1258, 0.1830, 0.1742, 0.1595, 0.1277, 0.1334, 0.1383, 0.1267, 0.1277, 0.1379, 0.1353, 0.1331, 0.1560, 0.1639, 0.1315, 0.1207, 0.1320, 0.1464, 0.1210, 0.1366, 0.1330, 0.1862, 0.1480, 0.1402, 0.1354, 0.1308, 0.1236, 0.1238, 0.1168, 0.1282, 0.1567, 0.1190, 0.1327, 0.1428, 0.1293, 0.1265, 0.1487, 0.1586, 0.1295, 0.1603, 0.1182, 0.1412, 0.1215, 0.1258, 0.1432, 0.1205, 0.1193, 0.1427, 0.1398, 0.1656, 0.1352, 0.1301, 0.1305, 0.1295, 0.1283, 0.1319, 0.1333, 0.1272, 0.1173, 0.1183, 0.1352, 0.1405, 0.1659, 0.1607, 0.1219, 0.1240, 0.1229, 0.1381, 0.1360, 0.1301, 0.1311, 0.1245, 0.1340, 0.1296, 0.1375, 0.1306, 0.1154, 0.1399, 0.1136, 0.1532, 0.1260, 0.1383, 0.1410, 0.1530, 0.1259, 0.1237, 0.1554, 0.1302, 0.1392, 0.1518, 0.1674, 0.1279, 0.1346, 0.1399, 0.1606, 0.1288, 0.1232, 0.1248, 0.1243, 0.1296, 0.1160, 0.1324, 0.1399, 0.1285, 0.1303, 0.1376, 0.1148, 0.1387, 0.1255, 0.1354, 0.1489, 0.1132, 0.1521, 0.1292, 0.1193, 0.1339, 0.1351, 0.1321, 0.1198, 0.1492, 0.1322, 0.1224, 0.1384, 0.1515, 0.1444, 0.1371, 0.1547, 0.1559, 0.1219, 0.1771, 0.1324, 0.1382, 0.1425, 0.1242, 0.1386, 0.1312, 0.1390, 0.1253, 0.1340, 0.1301, 0.1354, 0.1636, 0.1338, 0.1394, 0.1592, 0.1702, 0.1298, 0.1213, 0.1537, 0.1255, 0.1336], grad_fn=<MaxBackward0>)
In [198]:
labels
Out[198]:
tensor([3, 5, 8, 1, 1, 4, 6, 5, 1, 3, 4, 5, 5, 0, 4, 9, 8, 0, 7, 8, 8, 8, 1, 4,
        6, 3, 1, 5, 7, 1, 3, 3, 6, 2, 9, 0, 5, 9, 2, 9, 7, 9, 8, 6, 2, 0, 8, 0,
        1, 1, 2, 3, 9, 6, 8, 0, 5, 0, 9, 5, 9, 0, 8, 6, 5, 1, 3, 5, 2, 3, 2, 0,
        9, 3, 9, 3, 4, 3, 5, 1, 4, 9, 9, 3, 5, 2, 3, 7, 8, 3, 5, 1, 1, 7, 9, 9,
        8, 5, 6, 2, 9, 3, 9, 4, 5, 5, 7, 2, 1, 9, 3, 6, 8, 9, 9, 0, 4, 5, 4, 1,
        5, 3, 1, 7, 2, 3, 7, 5, 7, 1, 8, 7, 5, 8, 4, 8, 6, 9, 4, 8, 7, 8, 2, 3,
        5, 2, 9, 1, 4, 5, 2, 9, 5, 6, 5, 8, 0, 4, 6, 0, 7, 9, 5, 7, 5, 9, 9, 4,
        9, 0, 0, 6, 0, 4, 0, 8, 6, 9, 0, 8, 7, 1, 7, 8, 1, 9, 4, 9, 7, 9, 8, 7,
        8, 8, 2, 5, 9, 2, 7, 0])
In [199]:
jovian.commit()
[jovian] Saving notebook..
[jovian] Updating notebook "2bb6249741384832bcc18ab47036e211" on https://jovian.ml/ [jovian] Uploading notebook.. [jovian] Capturing environment.. [jovian] Recording metrics & hyperparameters.. [jovian] Committed successfully! https://jovian.ml/walid-gomaa/image-classification

Evalaution Metric and Loss Function

In [200]:
def accuracy(l1, l2):
    return torch.sum(l1 == l2).item() / len(l1)
In [201]:
torch.sum(labels == preds).item() / len(labels)
Out[201]:
0.115
In [202]:
loss_fn = F.cross_entropy
In [203]:
# Loss for the current batch of data.
loss = loss_fn(outputs, labels)
print(loss)
tensor(2.3260, grad_fn=<NllLossBackward>)
In [204]:
print(loss.item())
2.3259637355804443

Optimizer

In [205]:
learning_rate = 0.001
optimizer = torch.optim.SGD(model.parameters(), lr = learning_rate)

Training the model

In [206]:
def loss_batch(model, loss_func, xb, yb, opt = None, metric = None):
    # Calculate loss for a batch of data.
    preds = model(xb)
    loss = loss_func(preds, yb)
    
    if opt is not None:
        # Compute gradients.
        loss.backward()
        # Update parameters.
        opt.step()
        # Reset gradients.
        opt.zero_grad()
    metric_result = None
    if metric is not None:
        # Compute the metric.
        metric_result = metric(preds, yb)
        
    return loss.item(), len(xb), metric_result
In [207]:
def evaluate(model, loss_fn, valid_dl, metric = None):
    with torch.no_grad():
        # Pass each batch through the model.
        results = [loss_batch(model, loss_fn, xb, yb, metric = metric) for xb, yb in valid_dl]
        # Separate losses, counts, and metrics.
        losses, nums, metrics = zip(*results)
        # Total size of the dataset.
        total = np.sum(nums)
        # Average loss across batches.
        avg_loss = np.sum(np.multiply(losses, nums)) / total
        avg_metric = None
        if metric is not None:
            # Average of metric across batches.
            avg_metric = np.sum(np.multiply(metrics, nums)) / total
        return avg_loss, total, avg_metric
In [208]:
L = [(1,'e',1.2), (40,'er',5.9), (5,'w',3.5)]
In [209]:
a,b,c = zip(*L)
In [210]:
type(a)
Out[210]:
tuple
In [211]:
a
Out[211]:
(1, 40, 5)
In [212]:
b
Out[212]:
('e', 'er', 'w')
In [213]:
c
Out[213]:
(1.2, 5.9, 3.5)
In [214]:
[]
Out[214]:
[]
In [215]:
def accuracy(outputs, labels):
    _, preds = torch.max(outputs, dim = 1)
    return torch.sum(preds == labels).item() / len(preds)
In [216]:
ddd = np.array([[1,2,3], [4,5,6], [7,8,9]])
In [217]:
ddd
Out[217]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
In [218]:
ddd = torch.tensor(ddd)
In [219]:
a, b = torch.max(ddd, dim = 1)
In [220]:
torch.tensor(ddd)
/anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages/ipykernel_launcher.py:1: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor). """Entry point for launching an IPython kernel.
Out[220]:
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
In [221]:
b
Out[221]:
tensor([2, 2, 2])
In [222]:
val_loss, total, val_acc = evaluate(model, loss_fn, val_loader, metric = accuracy)
In [223]:
print("Loss: {:.4f}, Accuracy: {:.4f}".format(val_loss, val_acc))
Loss: 2.3232, Accuracy: 0.1177
In [224]:
def fit(epochs, model, loss_fn, opt, train_dl, valid_dl, metric = None):
    for epoch in range(epochs):
        # Training
        for xb, yb in train_dl:
            loss, _, _ = loss_batch(model, loss_fn, xb, yb, opt)
            
        # Evaluation.
        result = evaluate(model, loss_fn, valid_dl, metric)
        val_loss, total, val_metric = result
        
        # Print progress.
        if metric is None:
            print("Epoch [{}/{}], Loss: {:.4f}".format(epoch+1, epochs, val_loss))
        else:
            print("Epoch [{}/{}], Loss: {:.4f}, {}: {:.4f}".format(epoch+1, epochs, val_loss, metric.__name__, val_metric))
In [225]:
a,b,c = (1,2,3)
In [226]:
a
Out[226]:
1
In [227]:
b
Out[227]:
2
In [228]:
c
Out[228]:
3
In [229]:
# Redefine the model and the optimizer.
model = MnistModel()
optimizer = torch.optim.SGD(model.parameters(), lr = learning_rate)
In [ ]:
# Kick off the training process.
fit(15, model, F.cross_entropy, optimizer, train_loader, val_loader, accuracy)
Epoch [1/15], Loss: 2.0898, accuracy: 0.4723 Epoch [2/15], Loss: 1.8914, accuracy: 0.6647 Epoch [3/15], Loss: 1.7264, accuracy: 0.7208 Epoch [4/15], Loss: 1.5884, accuracy: 0.7474 Epoch [5/15], Loss: 1.4729, accuracy: 0.7643 Epoch [6/15], Loss: 1.3756, accuracy: 0.7777 Epoch [7/15], Loss: 1.2932, accuracy: 0.7863 Epoch [8/15], Loss: 1.2229, accuracy: 0.7927 Epoch [9/15], Loss: 1.1624, accuracy: 0.7992 Epoch [10/15], Loss: 1.1098, accuracy: 0.8053 Epoch [11/15], Loss: 1.0639, accuracy: 0.8094
In [125]:
accuracies = [0.4723, 0.6647, 0.7208, 0.7474, 0.7643, 0.7777, ]
In [129]:
plt.plot(accuracies, '-x')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.title('Accuracy vs. No. of epochs')
Out[129]:
Text(0.5, 1.0, 'Accuracy vs. No. of epochs')
Notebook Image
In [131]:
import jovian
In [135]:
jovian.log_hyperparams({
    'opt': 'SGD',
    'lr': 0.001,
    'batch_size': 100,
    'arch': 'logistic-regression'
})
[jovian] Hyperparameters logged.
In [130]:
!pip install jovian --upgrade
Collecting jovian Downloading https://files.pythonhosted.org/packages/b8/a1/dd7b5bcf0a3f043c894151f5e523c1f88ab72ed5672694f325e2f39e85f1/jovian-0.1.97-py2.py3-none-any.whl (50kB) |████████████████████████████████| 51kB 218kB/s eta 0:00:01 Collecting click Downloading https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl (81kB) |████████████████████████████████| 81kB 480kB/s eta 0:00:01 Requirement already satisfied, skipping upgrade: uuid in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from jovian) (1.30) Requirement already satisfied, skipping upgrade: pyyaml in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from jovian) (5.1.2) Requirement already satisfied, skipping upgrade: requests in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from jovian) (2.22.0) Requirement already satisfied, skipping upgrade: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from requests->jovian) (1.25.7) Requirement already satisfied, skipping upgrade: idna<2.9,>=2.5 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from requests->jovian) (2.8) Requirement already satisfied, skipping upgrade: chardet<3.1.0,>=3.0.2 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from requests->jovian) (3.0.4) Requirement already satisfied, skipping upgrade: certifi>=2017.4.17 in /anaconda3/envs/01-pytorch-basics/lib/python3.7/site-packages (from requests->jovian) (2019.9.11) Installing collected packages: click, jovian Found existing installation: jovian 0.1.89 Uninstalling jovian-0.1.89: Successfully uninstalled jovian-0.1.89 Successfully installed click-7.0 jovian-0.1.97
In [136]:
jovian.log_metrics({
    'val_loss': 0.6901,
    'val_acc': 0.8508
}
)
[jovian] Metrics logged.

Testing with individual images

In [137]:
# Define test dataset
test_dataset = MNIST(root = 'data/',
                    train = False,
                    transform = transforms.ToTensor())
In [145]:
img, label = test_dataset[0]
plt.imshow(img[0], cmap = 'gray')
print('Shape: ', img.shape)
print('Label: ', label)
Shape: torch.Size([1, 28, 28]) Label: 7
Notebook Image
In [141]:
type(img)
Out[141]:
torch.Tensor
In [146]:
img.unsqueeze(0).shape
Out[146]:
torch.Size([1, 1, 28, 28])
In [150]:
def predict_image(img, model):
    xb = img.unsqueeze(0)
    yb = model(xb)
    _, preds = torch.max(yb, dim = 1)
    return preds[0].item()
In [151]:
img, label = test_dataset[0]
plt.imshow(img[0], cmap = 'gray')
print("Label: ", label, ", predicted: ", predict_image(img, model))
Label: 7 , predicted: 7
Notebook Image
In [152]:
img, label = test_dataset[10]
plt.imshow(img[0], cmap = 'gray')
print("Label: ", label, ", predicted: ", predict_image(img, model))
Label: 0 , predicted: 0
Notebook Image
In [153]:
img, label = test_dataset[193]
plt.imshow(img[0], cmap = 'gray')
print("Label: ", label, ", predicted: ", predict_image(img, model))
Label: 9 , predicted: 9
Notebook Image
In [154]:
img, label = test_dataset[1839]
plt.imshow(img[0], cmap = 'gray')
print("Label: ", label, ", predicted: ", predict_image(img, model))
Label: 2 , predicted: 8
Notebook Image
In [157]:
test_loader = DataLoader(test_dataset, batch_size = 200)
test_loss, total, test_acc = evaluate(model, loss_fn, test_loader, metric = accuracy)
In [158]:
print("Loss: {:.4f}, Accuracy: {:.4f}".format(test_loss, test_acc))
Loss: 0.6641, Accuracy: 0.8605
In [159]:
jovian.log_metrics({
    'test_loss': 0.6641,
    'test_acc': 0.8605
}
)
[jovian] Metrics logged.

Saving and loading the model

In [160]:
torch.save(model.state_dict(), 'mnist-logistic.pth')
In [162]:
model.state_dict()
Out[162]:
OrderedDict([('linear.weight',
              tensor([[-0.0050,  0.0228,  0.0005,  ..., -0.0028, -0.0125,  0.0313],
                      [-0.0074,  0.0066,  0.0028,  ..., -0.0018,  0.0146,  0.0251],
                      [ 0.0250,  0.0014, -0.0204,  ..., -0.0181,  0.0210,  0.0165],
                      ...,
                      [-0.0131, -0.0189,  0.0042,  ...,  0.0254, -0.0280,  0.0258],
                      [ 0.0298,  0.0060,  0.0350,  ...,  0.0153, -0.0047, -0.0192],
                      [ 0.0031, -0.0298,  0.0008,  ..., -0.0207,  0.0282,  0.0073]])),
             ('linear.bias',
              tensor([-0.0429,  0.0826, -0.0189, -0.0235,  0.0544,  0.0241, -0.0437,  0.0425,
                      -0.0751, -0.0003]))])
In [165]:
model2 = MnistModel()
model2.load_state_dict(torch.load('mnist-logistic.pth'))
Out[165]:
<All keys matched successfully>
In [166]:
model2.state_dict()
Out[166]:
OrderedDict([('linear.weight',
              tensor([[-0.0050,  0.0228,  0.0005,  ..., -0.0028, -0.0125,  0.0313],
                      [-0.0074,  0.0066,  0.0028,  ..., -0.0018,  0.0146,  0.0251],
                      [ 0.0250,  0.0014, -0.0204,  ..., -0.0181,  0.0210,  0.0165],
                      ...,
                      [-0.0131, -0.0189,  0.0042,  ...,  0.0254, -0.0280,  0.0258],
                      [ 0.0298,  0.0060,  0.0350,  ...,  0.0153, -0.0047, -0.0192],
                      [ 0.0031, -0.0298,  0.0008,  ..., -0.0207,  0.0282,  0.0073]])),
             ('linear.bias',
              tensor([-0.0429,  0.0826, -0.0189, -0.0235,  0.0544,  0.0241, -0.0437,  0.0425,
                      -0.0751, -0.0003]))])
In [168]:
test_loss, _, test_acc = evaluate(model2, loss_fn, test_loader, metric = accuracy)
In [169]:
print("Loss: {:.4f}, Accuracy: {:.4f}".format(test_loss, test_acc))
Loss: 0.6641, Accuracy: 0.8605

Commit and upload the notebook.

In [170]:
import jovian
In [171]:
jovian.commit(artifacts = ['mnist-logistic.pth'])
[jovian] Saving notebook..
[jovian] Updating notebook "2bb6249741384832bcc18ab47036e211" on https://jovian.ml/ [jovian] Uploading notebook.. [jovian] Capturing environment.. [jovian] Uploading artifacts.. [jovian] Recording metrics & hyperparameters.. [jovian] Committed successfully! https://jovian.ml/walid-gomaa/image-classification
In [ ]: