HTML generated from Jupyter notebook: regression-one-hidden-layer.ipynb

Regression with one hidden layer

In [1]:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
%matplotlib inline

import pprint as pp

import torch
import torch.nn as nn
from torch.utils.data import DataLoader

Test data

In [2]:
np.random.seed(0)

n_samples = 10
x = np.arange(n_samples)
y = np.sin(2 * np.pi * x / n_samples) * 4

plt.figure(figsize=(4,4))
plt.plot(x, y, 'o')
plt.xlabel('x')
plt.ylabel('y')
plt.xlim(-1,10)
plt.ylim(-5,5)
Out[2]:
(-5, 5)

Torch dataset

We will create a dataset class that will be used by dataloader to present batches during training.

In [3]:
from torch.utils.data import Dataset
class MyDataset(Dataset):
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __len__(self):
        return len(self.x)
    
    def __getitem__(self, idx):
        sample = {
            'feature': torch.tensor([self.x[idx]], dtype=torch.float32), 
            'label': torch.tensor(np.array([self.y[idx]]), dtype=torch.float32)}
        return sample

Testing our dataset.

In [4]:
import pprint as pp

dataset = MyDataset(x, y)
print('length: ', len(dataset))
for i in range(5):
    pp.pprint(dataset[i])
length:  10
{'feature': tensor([0.]), 'label': tensor([0.])}
{'feature': tensor([1.]), 'label': tensor([2.3511])}
{'feature': tensor([2.]), 'label': tensor([3.8042])}
{'feature': tensor([3.]), 'label': tensor([3.8042])}
{'feature': tensor([4.]), 'label': tensor([2.3511])}

Using dataloader to construct batches for training purposes

In [5]:
dataset = MyDataset(x, y)
batch_size = 4
shuffle = True
num_workers = 4
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers)
for i_batch, samples in enumerate(dataloader):
    print('\nbatch# = %s' % i_batch)
    print('samples: ')
    pp.pprint(samples)
    break # Otherwise it prints too much stuff
batch# = 0
samples: 
{'feature': tensor([[9.],
        [6.],
        [5.],
        [0.]]),
 'label': tensor([[-2.3511],
        [-2.3511],
        [ 0.0000],
        [ 0.0000]])}

Logistic regression model

In [6]:
class Regression(nn.Module):
    def __init__(self, input_size):
        super(Regression, self).__init__()
        
        # input layer
        self.linear1 = nn.Linear(input_size, 10)
        self.tan1 = nn.Tanh()
        
        # hidden layer
        self.linear2 = nn.Linear(10, 10)
        self.tan2 = nn.Tanh()
        
        # output layer -- Sigmoid since we are interested in classification
        self.linear3 = nn.Linear(10, 1)
    
    def forward(self, x):
       # input layer
        out = self.tan1(self.linear1(x))
        
        # hidden layer
        out = self.tan2(self.linear2(out))

        # output layer -- No Sigmoid since we are interested in regression
        out = self.linear3(out)
        
        return out

Loss

In [7]:
import torch.nn as nn
class MyLoss(nn.Module):
    def __init__(self):
        super(MyLoss, self).__init__()
        
    def forward(self, predictions, targets):
#        print(predictions.shape)
#        print(targets.shape)
        d = torch.sub(predictions, targets)
        d2 = torch.pow(d, 2)
        d2sum = torch.sum(d2)
        
        return d2sum

Accuracy

Counting how many predictions were correct.

In [8]:
def accuracy(predictions, targets):
    d = torch.sub(predictions, targets)
    d2 = torch.pow(d, 2)
    d2sum = torch.sum(d2)
    return d2sum.item()

Training

In [9]:
import torch.nn.functional as F

model = Regression(1)
criterion = MyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)  

dataset = MyDataset(x, y)
batch_size = 16
shuffle = True
num_workers = 4
training_sample_generator = DataLoader(dataset, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers)

num_epochs = 5000
for epoch in range(num_epochs):
    n = 0
    for batch_i, samples in enumerate(training_sample_generator):
        predictions = model(samples['feature'])
        error = criterion(predictions, samples['label'])
        n += accuracy(predictions, samples['label'])
        optimizer.zero_grad()
        error.backward()        
        optimizer.step()
    if epoch % 200 == 0:
        print('epoch %d:' % epoch, error.item())
        print('accuracy', n)
epoch 0: 81.23841094970703
accuracy 81.23841094970703
epoch 200: 72.55889129638672
accuracy 72.55889129638672
epoch 400: 133.5906219482422
accuracy 133.5906219482422
epoch 600: 64.32172393798828
accuracy 64.32172393798828
epoch 800: 73.838134765625
accuracy 73.838134765625
epoch 1000: 73.7865219116211
accuracy 73.7865219116211
epoch 1200: 73.78073120117188
accuracy 73.78073120117188
epoch 1400: 73.77579498291016
accuracy 73.77579498291016
epoch 1600: 73.76687622070312
accuracy 73.76687622070312
epoch 1800: 73.69158172607422
accuracy 73.69158172607422
epoch 2000: 73.77983093261719
accuracy 73.77983093261719
epoch 2200: 73.77928924560547
accuracy 73.77928924560547
epoch 2400: 73.7784423828125
accuracy 73.7784423828125
epoch 2600: 73.77693939208984
accuracy 73.77693939208984
epoch 2800: 73.77369689941406
accuracy 73.77369689941406
epoch 3000: 73.76445007324219
accuracy 73.76445007324219
epoch 3200: 73.74217987060547
accuracy 73.74217987060547
epoch 3400: 10.747784614562988
accuracy 10.747784614562988
epoch 3600: 5.925016403198242
accuracy 5.925016403198242
epoch 3800: 3.5058584213256836
accuracy 3.5058584213256836
epoch 4000: 17.074453353881836
accuracy 17.074453353881836
epoch 4200: 3.3848962783813477
accuracy 3.3848962783813477
epoch 4400: 3.196403741836548
accuracy 3.196403741836548
epoch 4600: 3.204854965209961
accuracy 3.204854965209961
epoch 4800: 3.0956640243530273
accuracy 3.0956640243530273

Visualizing results

In [11]:
x_try = torch.tensor(x, dtype=torch.float32)
print(x_try.unsqueeze(1))

y_try = model(x_try.unsqueeze(1))
yy_try = y_try.detach().squeeze().numpy()
print(yy_try)

plt.figure(figsize=(4,4))
plt.plot(x, y, 'o', label='Ground truth')
plt.plot(x, yy_try, 'x', label='Prediction')
plt.xlabel('x')
plt.ylabel('y')
plt.xlim(-1,10)
plt.ylim(-5,5)
plt.legend()
tensor([[0.],
        [1.],
        [2.],
        [3.],
        [4.],
        [5.],
        [6.],
        [7.],
        [8.],
        [9.]])
[ 1.1032820e-04  2.3362899e+00  3.6030660e+00  2.9903252e+00
  2.8890362e+00 -1.7187625e-01 -3.1443129e+00 -3.2978761e+00
 -3.2996073e+00 -3.2996252e+00]
Out[11]:
<matplotlib.legend.Legend at 0x118cf8898>