text_plain_output_1.png image_output_1.png
from torch.utils.data import Dataset, DataLoader

import matplotlib.pyplot as plt

import numpy as np

import pandas as pd

import torch

import torch.nn as nn

import torch.optim as optim

BATCH_SIZE = 16
LEARNING_RATE = 0.001
N_EPOCHS = 20
LAYER1_SIZE = 256
LAYER2_SIZE = 256
DROPOUT_RATE = 0.3

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
device

train_data = pd.read_csv('../input/digit-recognizer/train.csv')
test_data = pd.read_csv('../input/digit-recognizer/test.csv') / 255

# Figure size
plt.figure(figsize=(8,8))

# Subplot
for i in range(9):
    img = np.asarray(train_data.iloc[i+180,1:].values.reshape((28,28))/255)
    ax=plt.subplot(3, 3, i+1)
    ax.grid(False)
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    ax.title.set_text(f'{train_data.iloc[i+18,0]}')
    plt.imshow(img, cmap='gray')
    
plt.show()

class MNIST(Dataset):
    def __init__(self, subset='train'):
        super().__init__()
        self.subset = subset
        if self.subset == 'train':
            self.X = torch.from_numpy(X_train.values.astype(np.float32))
            self.y = torch.from_numpy(y_train.values)
        elif self.subset == 'valid':
            self.X = torch.from_numpy(X_valid.values.astype(np.float32))
            self.y = torch.from_numpy(y_valid.values)
        elif self.subset == 'test':
            self.X = torch.from_numpy(test_data.values.astype(np.float32))
        else:
            raise Exception('subset must be train, valid or test')
    def __getitem__(self, index):
        if self.subset == 'test':
            return self.X[index]
        else:
            return (self.X[index], self.y[index])
    def __len__(self):
        return self.X.shape[0]
train_dataset = MNIST(subset='train')
valid_dataset = MNIST(subset='valid')
test_dataset = MNIST(subset='test')

train_loader = DataLoader(dataset=train_dataset, batch_size=BATCH_SIZE, shuffle=True)
valid_loader = DataLoader(dataset=valid_dataset, batch_size=BATCH_SIZE, shuffle=False)
test_loader = DataLoader(dataset=test_dataset, batch_size=BATCH_SIZE, shuffle=False)

class NeuralNet(nn.Module):
    def __init__(self, layer1_size=LAYER1_SIZE, layer2_size=LAYER2_SIZE, dropout_rate=DROPOUT_RATE):
        super().__init__()
        self.lin1 = nn.Linear(in_features=784, out_features=layer1_size)
        self.lin2 = nn.Linear(in_features=layer1_size, out_features=layer2_size)
        self.lin3 = nn.Linear(in_features=layer2_size, out_features=10)
        self.relu = nn.ReLU()
        self.drop = nn.Dropout(p=dropout_rate)
    def forward(self, x):
        out = self.lin1(x)
        out = self.relu(out)
        out = self.drop(out)
        out = self.lin2(out)
        out = self.relu(out)
        out = self.drop(out)
        out = self.lin3(out)
        return out
model = NeuralNet().to(device)

loss = nn.CrossEntropyLoss()
optimiser = optim.Adam(params=model.parameters(), lr=LEARNING_RATE)

loss_hist = []
val_loss_hist = []
for epoch in range(N_EPOCHS):
    loss_acc = 0
    val_loss_acc = 0
    train_count = 0
    valid_count = 0
    for imgs, labels in train_loader:
        imgs = imgs.to(device)
        labels = labels.to(device)
        preds = model(imgs)
        L = loss(preds, labels)
        L.backward()
        optimiser.step()
        optimiser.zero_grad()
        loss_acc += L.detach().item()
        train_count += 1
    with torch.no_grad():
        for val_imgs, val_labels in valid_loader:
            val_imgs = val_imgs.to(device)
            val_labels = val_labels.to(device)
            val_preds = model(val_imgs)
            val_L = loss(val_preds, val_labels)
            val_loss_acc += val_L.item()
            valid_count += 1
    loss_hist.append(loss_acc / train_count)
    val_loss_hist.append(val_loss_acc / valid_count)
    if (epoch + 1) % 5 == 0:
        print(f'Epoch {epoch + 1}/{N_EPOCHS}, loss {loss_acc / train_count:.5f}, val_loss {val_loss_acc / valid_count:.5f}')