Overfitting and regularization from scratch


In [1]:
from __future__ import print_function
import mxnet as mx
import numpy as np
from tqdm import tqdm
ctx = mx.cpu()
mx.random.seed(69)


C:\ProgramData\Anaconda3\lib\site-packages\h5py\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
C:\ProgramData\Anaconda3\lib\site-packages\h5py\tests\old\test_attrs_data.py:251: DeprecationWarning: invalid escape sequence \H
  s = b"Hello\x00\Hello"
C:\ProgramData\Anaconda3\lib\site-packages\sklearn\externals\joblib\func_inspect.py:53: DeprecationWarning: invalid escape sequence \<
  '\<doctest (.*\.rst)\[(.*)\]\>', source_file).groups()
C:\ProgramData\Anaconda3\lib\site-packages\sklearn\externals\joblib\_memory_helpers.py:10: DeprecationWarning: invalid escape sequence \s
  cookie_re = re.compile("coding[:=]\s*([-\w.]+)")

In [2]:
%matplotlib inline
#import matplotlib
import matplotlib.pyplot as plt

Loading the MNIST dataset


In [3]:
mnist = mx.test_utils.get_mnist()
num_examples = 1000
batch_size = 64
train_data = mx.gluon.data.DataLoader(
    mx.gluon.data.ArrayDataset(mnist["train_data"][:num_examples],
                               mnist["train_label"][:num_examples].astype(np.float32)),
                               batch_size, shuffle=True)
test_data = mx.gluon.data.DataLoader(
    mx.gluon.data.ArrayDataset(mnist["test_data"][:num_examples],
                               mnist["test_label"][:num_examples].astype(np.float32)),
                               batch_size, shuffle=False)

Initializing model parameters


In [4]:
W = mx.nd.random_normal(shape=(784,10))
b = mx.nd.random_normal(shape=10)

params = [W, b]

In [5]:
# Gradients
for param in params:
    param.attach_grad()

Defining the model


In [6]:
def net(X):
    y_linear = mx.nd.dot(X, W) + b
    yhat = mx.nd.softmax(y_linear, axis=1)
    return yhat

Loss function


In [7]:
def cross_entropy(yhat, y):
    return - mx.nd.sum(y * mx.nd.log(yhat), 
                       axis=0, 
                       exclude=True)

Optimizer - Stochastic Gradient Descent


In [8]:
def SGD(params, lr):
    for param in params:
        param[:] = param - lr * param.grad

Accuracy evaluation


In [9]:
def evaluate_accuracy(data_iterator, net):
    numerator = 0.
    denominator = 0.
    loss_avg = 0.
    for i, (data, label) in enumerate(data_iterator):
        data = data.as_in_context(ctx).reshape((-1,784))
        label = label.as_in_context(ctx)
        label_one_hot = mx.nd.one_hot(label, 10)
        output = net(data)
        loss = cross_entropy(output, label_one_hot)
        predictions = mx.nd.argmax(output, axis=1)
        numerator += mx.nd.sum(predictions == label)
        denominator += data.shape[0]
        loss_avg = loss_avg * i / (i + 1) + mx.nd.mean(loss).asscalar() / (i + 1)
    return (numerator / denominator).asscalar(), loss_avg

Learning curves


In [10]:
def plot_learningcurves(loss_tr,loss_ts, acc_tr,acc_ts):
    xs = list(range(len(loss_tr)))

    f = plt.figure(figsize=(12, 6))
    fg1 = f.add_subplot(121)
    fg2 = f.add_subplot(122)

    fg1.set_xlabel('epoch', fontsize=14)
    fg1.set_title('Comparing loss functions')
    fg1.semilogy(xs, loss_tr)
    fg1.semilogy(xs, loss_ts)
    fg1.grid(True,which="both")

    fg1.legend(['training loss', 'testing loss'], fontsize=14)

    fg2.set_title('Comparing accuracy')
    fg1.set_xlabel('epoch', fontsize=14)
    fg2.plot(xs, acc_tr)
    fg2.plot(xs, acc_ts)
    fg2.grid(True, which="both")
    fg2.legend(['training accuracy', 'testing accuracy'], fontsize=14)

Training loop


In [11]:
# Hyperparameters
epochs = 2000

In [12]:
moving_loss = 0.
niter=0

loss_seq_train = []
loss_seq_test = []
acc_seq_train = []
acc_seq_test = []

In [13]:
for e in tqdm(range(epochs)):
    for i, (data, label) in enumerate(train_data):
        data = data.as_in_context(ctx).reshape((-1,784))
        label = label.as_in_context(ctx)
        label_one_hot = mx.nd.one_hot(label, 10)
        with mx.autograd.record():
            output = net(data)
            loss = cross_entropy(output, label_one_hot)
        loss.backward()
        SGD(params, .001)

        ##########################
        #  Keep a moving average of the losses
        ##########################
        niter +=1
        moving_loss = .99 * moving_loss + .01 * mx.nd.mean(loss).asscalar()
        est_loss = moving_loss/(1-0.99**niter)

    test_accuracy, test_loss = evaluate_accuracy(test_data, net)
    train_accuracy, train_loss = evaluate_accuracy(train_data, net)

    # save them for later
    loss_seq_train.append(train_loss)
    loss_seq_test.append(test_loss)
    acc_seq_train.append(train_accuracy)
    acc_seq_test.append(test_accuracy)


    if e % 100 == 99:
        print("Completed epoch %s. Train Loss: %s, Test Loss %s, Train_acc %s, Test_acc %s" %
              (e+1, train_loss, test_loss, train_accuracy, test_accuracy))


  5%|████████▍                                                                                                                                                                  | 98/2000 [00:05<01:51, 17.07it/s]
Completed epoch 100. Train Loss: 0.6038771346211435, Test Loss 1.599613390862942, Train_acc 0.856, Test_acc 0.686
 10%|████████████████▊                                                                                                                                                         | 198/2000 [00:11<01:44, 17.28it/s]
Completed epoch 200. Train Loss: 0.2768279858864844, Test Loss 1.4021890088915827, Train_acc 0.931, Test_acc 0.716
 15%|█████████████████████████▎                                                                                                                                                | 298/2000 [00:17<01:37, 17.53it/s]
Completed epoch 300. Train Loss: 0.1489952034316957, Test Loss 1.346388429403305, Train_acc 0.966, Test_acc 0.734
 20%|█████████████████████████████████▊                                                                                                                                        | 398/2000 [00:22<01:30, 17.66it/s]
Completed epoch 400. Train Loss: 0.09579754318110646, Test Loss 1.3299146555364134, Train_acc 0.985, Test_acc 0.74
 25%|██████████████████████████████████████████▍                                                                                                                               | 499/2000 [00:28<01:25, 17.64it/s]
Completed epoch 500. Train Loss: 0.06077140453271568, Test Loss 1.3234415017068384, Train_acc 0.994, Test_acc 0.744
 30%|██████████████████████████████████████████████████▊                                                                                                                       | 598/2000 [00:33<01:18, 17.84it/s]
Completed epoch 600. Train Loss: 0.04422907129628584, Test Loss 1.3154895789921284, Train_acc 0.999, Test_acc 0.747
 35%|███████████████████████████████████████████████████████████▍                                                                                                              | 699/2000 [00:38<01:12, 18.05it/s]
Completed epoch 700. Train Loss: 0.03473750373814256, Test Loss 1.3065832294523714, Train_acc 1.0, Test_acc 0.752
 40%|███████████████████████████████████████████████████████████████████▉                                                                                                      | 799/2000 [00:44<01:06, 18.14it/s]
Completed epoch 800. Train Loss: 0.028673032415099442, Test Loss 1.2999009974300861, Train_acc 1.0, Test_acc 0.754
 45%|████████████████████████████████████████████████████████████████████████████▍                                                                                             | 899/2000 [00:49<01:00, 18.21it/s]
Completed epoch 900. Train Loss: 0.02438156516291201, Test Loss 1.2950564920902252, Train_acc 1.0, Test_acc 0.755
 50%|████████████████████████████████████████████████████████████████████████████████████▉                                                                                     | 999/2000 [00:55<00:55, 17.91it/s]
Completed epoch 1000. Train Loss: 0.02146818581968546, Test Loss 1.2915939725935455, Train_acc 1.0, Test_acc 0.756
 55%|████████████████████████████████████████████████████████████████████████████████████████████▊                                                                            | 1099/2000 [01:02<00:50, 17.71it/s]
Completed epoch 1100. Train Loss: 0.0192582905292511, Test Loss 1.2890733741223812, Train_acc 1.0, Test_acc 0.759
 60%|█████████████████████████████████████████████████████████████████████████████████████████████████████▎                                                                   | 1199/2000 [01:08<00:45, 17.62it/s]
Completed epoch 1200. Train Loss: 0.017185447621159252, Test Loss 1.2872272171080112, Train_acc 1.0, Test_acc 0.763
 65%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████▊                                                           | 1299/2000 [01:14<00:39, 17.53it/s]
Completed epoch 1300. Train Loss: 0.015476226515602317, Test Loss 1.2859580721706154, Train_acc 1.0, Test_acc 0.762
 70%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏                                                  | 1399/2000 [01:20<00:34, 17.30it/s]
Completed epoch 1400. Train Loss: 0.014637210289947689, Test Loss 1.2850818559527393, Train_acc 1.0, Test_acc 0.764
 75%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▋                                          | 1499/2000 [01:27<00:29, 17.07it/s]
Completed epoch 1500. Train Loss: 0.013286375382449478, Test Loss 1.28445459716022, Train_acc 1.0, Test_acc 0.766
 80%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████                                  | 1599/2000 [01:34<00:23, 16.99it/s]
Completed epoch 1600. Train Loss: 0.012350540840998294, Test Loss 1.284093173220754, Train_acc 1.0, Test_acc 0.768
 85%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▌                         | 1699/2000 [01:39<00:17, 17.05it/s]
Completed epoch 1700. Train Loss: 0.011432135128416124, Test Loss 1.2839696779847143, Train_acc 1.0, Test_acc 0.768
 90%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████                 | 1799/2000 [01:45<00:11, 17.05it/s]
Completed epoch 1800. Train Loss: 0.010793417692184448, Test Loss 1.2838998492807152, Train_acc 1.0, Test_acc 0.767
 95%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▍        | 1899/2000 [01:51<00:05, 17.11it/s]
Completed epoch 1900. Train Loss: 0.010174113151151689, Test Loss 1.2840129863470795, Train_acc 1.0, Test_acc 0.768
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉| 1999/2000 [01:56<00:00, 17.15it/s]
Completed epoch 2000. Train Loss: 0.009524914174107831, Test Loss 1.2842037398368116, Train_acc 1.0, Test_acc 0.77
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2000/2000 [01:56<00:00, 17.15it/s]

In [14]:
## Plotting the learning curves
plot_learningcurves(loss_seq_train, loss_seq_test, acc_seq_train, acc_seq_test)


L2 Penalty


In [15]:
def l2_penalty(params):
    penalty = mx.nd.zeros(shape=1)
    for param in params:
        penalty = penalty + mx.nd.sum(param ** 2)
    return penalty

Re-initializing the parameters with the penalty


In [16]:
for param in params:
    param[:] = mx.nd.random_normal(shape=param.shape)

Training with L2 Penalty


In [17]:
epochs = 2000
moving_loss = 0.
l2_strength = .1

In [18]:
niter = 0

loss_seq_train = []
loss_seq_test = []
acc_seq_train = []
acc_seq_test = []

In [19]:
for e in tqdm(range(epochs)):
    for i, (data, label) in enumerate(train_data):
        data = data.as_in_context(ctx).reshape((-1,784))
        label = label.as_in_context(ctx)
        label_one_hot = mx.nd.one_hot(label, 10)
        with mx.autograd.record():
            output = net(data)
            loss = mx.nd.sum(cross_entropy(output, label_one_hot)) + l2_strength * l2_penalty(params)
        loss.backward()
        SGD(params, .001)

        ##########################
        #  Keep a moving average of the losses
        ##########################
        niter +=1
        moving_loss = .99 * moving_loss + .01 * mx.nd.mean(loss).asscalar()
        est_loss = moving_loss/(1-0.99**niter)


    test_accuracy, test_loss = evaluate_accuracy(test_data, net)
    train_accuracy, train_loss = evaluate_accuracy(train_data, net)

    # save them for later
    loss_seq_train.append(train_loss)
    loss_seq_test.append(test_loss)
    acc_seq_train.append(train_accuracy)
    acc_seq_test.append(test_accuracy)

    if e % 100 == 99:
        print("Completed epoch %s. Train Loss: %s, Test Loss %s, Train_acc %s, Test_acc %s" %
              (e+1, train_loss, test_loss, train_accuracy, test_accuracy))


  5%|████████▍                                                                                                                                                                  | 98/2000 [00:06<02:09, 14.70it/s]
Completed epoch 100. Train Loss: 0.3659017644822597, Test Loss 1.1831470094621181, Train_acc 0.901, Test_acc 0.713
 10%|████████████████▊                                                                                                                                                         | 198/2000 [00:13<02:02, 14.66it/s]
Completed epoch 200. Train Loss: 0.17370473546907306, Test Loss 0.8214248269796371, Train_acc 0.966, Test_acc 0.766
 15%|█████████████████████████▎                                                                                                                                                | 298/2000 [00:20<01:56, 14.60it/s]
Completed epoch 300. Train Loss: 0.1360322600230575, Test Loss 0.667118364945054, Train_acc 0.983, Test_acc 0.794
 20%|█████████████████████████████████▊                                                                                                                                        | 398/2000 [00:27<01:49, 14.65it/s]
Completed epoch 400. Train Loss: 0.12753395223990086, Test Loss 0.5858515463769437, Train_acc 0.989, Test_acc 0.816
 25%|██████████████████████████████████████████▎                                                                                                                               | 498/2000 [00:33<01:42, 14.67it/s]
Completed epoch 500. Train Loss: 0.1274819583632052, Test Loss 0.5429002176970243, Train_acc 0.993, Test_acc 0.824
 30%|██████████████████████████████████████████████████▊                                                                                                                       | 598/2000 [00:40<01:35, 14.67it/s]
Completed epoch 600. Train Loss: 0.12687483662739396, Test Loss 0.5220139883458617, Train_acc 0.992, Test_acc 0.83
 35%|███████████████████████████████████████████████████████████▎                                                                                                              | 698/2000 [00:47<01:29, 14.54it/s]
Completed epoch 700. Train Loss: 0.12834594026207927, Test Loss 0.511879913508892, Train_acc 0.994, Test_acc 0.836
 40%|███████████████████████████████████████████████████████████████████▊                                                                                                      | 798/2000 [00:54<01:22, 14.57it/s]
Completed epoch 800. Train Loss: 0.13077487936243415, Test Loss 0.50735848210752, Train_acc 0.993, Test_acc 0.837
 45%|████████████████████████████████████████████████████████████████████████████▎                                                                                             | 898/2000 [01:01<01:15, 14.60it/s]
Completed epoch 900. Train Loss: 0.1288467608392239, Test Loss 0.5036889091134071, Train_acc 0.991, Test_acc 0.839
 50%|████████████████████████████████████████████████████████████████████████████████████▊                                                                                     | 998/2000 [01:09<01:09, 14.45it/s]
Completed epoch 1000. Train Loss: 0.12741930061019954, Test Loss 0.5019851829856634, Train_acc 0.994, Test_acc 0.839
 55%|████████████████████████████████████████████████████████████████████████████████████████████▊                                                                            | 1098/2000 [01:16<01:02, 14.41it/s]
Completed epoch 1100. Train Loss: 0.12783570494502783, Test Loss 0.5008499156683683, Train_acc 0.993, Test_acc 0.839
 60%|█████████████████████████████████████████████████████████████████████████████████████████████████████▏                                                                   | 1198/2000 [01:23<00:55, 14.42it/s]
Completed epoch 1200. Train Loss: 0.12979424605146053, Test Loss 0.5017950646579266, Train_acc 0.993, Test_acc 0.838
 65%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████▋                                                           | 1298/2000 [01:29<00:48, 14.43it/s]
Completed epoch 1300. Train Loss: 0.12912576040253043, Test Loss 0.5006001740694046, Train_acc 0.992, Test_acc 0.84
 70%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏                                                  | 1398/2000 [01:36<00:41, 14.46it/s]
Completed epoch 1400. Train Loss: 0.13007821282371876, Test Loss 0.4997680727392435, Train_acc 0.992, Test_acc 0.839
 75%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▌                                          | 1498/2000 [01:43<00:34, 14.48it/s]
Completed epoch 1500. Train Loss: 0.1285314322449267, Test Loss 0.49972583539783955, Train_acc 0.993, Test_acc 0.841
 80%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████                                  | 1598/2000 [01:50<00:27, 14.41it/s]
Completed epoch 1600. Train Loss: 0.12846492137759924, Test Loss 0.5000826939940453, Train_acc 0.991, Test_acc 0.841
 85%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▍                         | 1698/2000 [01:58<00:20, 14.38it/s]
Completed epoch 1700. Train Loss: 0.12928316881880164, Test Loss 0.5000155884772539, Train_acc 0.993, Test_acc 0.839
 90%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉                 | 1798/2000 [02:05<00:14, 14.35it/s]
Completed epoch 1800. Train Loss: 0.13013487542048097, Test Loss 0.4997349977493286, Train_acc 0.992, Test_acc 0.84
 95%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▍        | 1898/2000 [02:12<00:07, 14.33it/s]
Completed epoch 1900. Train Loss: 0.12985176499933004, Test Loss 0.5005729533731937, Train_acc 0.993, Test_acc 0.839
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▊| 1998/2000 [02:19<00:00, 14.30it/s]
Completed epoch 2000. Train Loss: 0.1300811441615224, Test Loss 0.5003355573862791, Train_acc 0.991, Test_acc 0.839
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2000/2000 [02:19<00:00, 14.30it/s]

In [20]:
# Plotting the learning curves
plot_learningcurves(loss_seq_train, loss_seq_test, acc_seq_train, acc_seq_test)