Import section

In [1]:
import numpy as np
In [2]:
import torch
from torch import nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
In [3]:
from ipywidgets import interact, interact_manual, interactive, fixed
import ipywidgets as widgets
from IPython.display import display

Section: MNIST HELPERS

In [4]:
def read(fileName):
    """ Lee las imágenes desde first hasta last y las almacena en un arreglo 2D,
    donde cada renglón corresponde a una imagen.
    """
    file = open(fileName, "rb")
    # Leer número mágico

    ## Los dos primeros bytes son cero
    byte = file.read(4)
    if byte[0] != 0 or byte[1] != 0:
        raise Error("Encabezado corrupto: deben ser ceros" + str(byte))
    ## El tercero codifica el tipo de datos:
    ## 0x08: unsigned byte
    ## 0x09: signed byte
    ## 0x0B: short (2 bytes)
    ## 0x0C: int (4 bytes)
    ## 0x0D: float (4 bytes)
    ## 0x0E: double (8 bytes)
    switcher = {
        0x08 : np.uint8,
        0x09 : np.int8,
        0x0B : np.int16,
        0x0C : np.int32,
        0x0D : np.float32,
        0x0E : np.float64,
    }
    dataType = switcher.get(byte[2], None)
    ## Número de dimensiones
    numDims = byte[3]
    ## Tamaño de cada dimensión (cada una es un int de 4 bytes MSB first)
    sizes = tuple(np.fromfile(file, dtype=np.int32, count=numDims).newbyteorder())
    print("Vector de ", numDims, " dimensiones: ", sizes, " tipo ", dataType)
    ## Resto
    a = np.fromfile(file, dtype=dataType)
    data = np.reshape(a, sizes)
    file.close()
    return data

def printFull(array):
    opt = np.get_printoptions()
    np.set_printoptions(threshold=np.inf)
    print(array)
    np.set_printoptions(**opt)


import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import warnings

from IPython.core.pylabtools import figsize

def muestraImagen(vector3D, labelsVector, indice):
    figsize(3, 3)
    plt.title(labelsVector[indice])
    # El -1 invierte el orden en y
    plt.pcolormesh(vector3D[indice][::-1], cmap=cm.winter)
    plt.show()

def muestraActividad(red, iEntrada):
    """ Grafica los valores de activación de cada neurona
    para la entrada en la columna iEntrada.
    """
    if(iEntrada > red.A0.shape[1]):
        raise IndexError("Ejemplar de entrenamiento inexistente " + str(iEntrada))
    nRens = 4
    nCols = 1

    fig, axes = plt.subplots(figsize=(6,4))
    norm = matplotlib.colors.Normalize(vmin=0, vmax=1)

    ax_0 = plt.subplot2grid((nRens,nCols), (2,0), rowspan=2)
    ax_1 = plt.subplot2grid((nRens,nCols), (1,0))
    ax_2 = plt.subplot2grid((nRens,nCols), (0,0), sharey=ax_1)

    a0 = red.A0[:,iEntrada]
    a1 = red.A1[:,iEntrada:iEntrada+1].T
    a2 = red.A2[:,iEntrada:iEntrada+1].T

    # A0
    ax_0.pcolormesh(a0[1:].reshape((28,28))[::-1], cmap=cm.cool, norm=norm)
    ax_0.set_xlim(0, 28)
    ax_0.set_ylim(0, 28)

    # A1
    ax_1.pcolormesh(a1, cmap=cm.cool, norm=norm)
    ax_1.set_yticks(np.array([0,1]))
    ax_1.set_xlim(0, 26)
    ax_1.set_xticks(np.arange(26) + 0.5)
    ax_1.set_xticklabels(np.arange(26), minor=False, ha='center')

    # A2
    ax_2.pcolormesh(a2, cmap=cm.cool, norm=norm)
    ax_2.set_xticks(np.arange(10) + 0.5)
    ax_2.set_xticklabels(np.arange(10), minor=False, ha='center')

    # Barra de color
    ax1 = fig.add_axes([1.0, 0, 0.025, 1.0]) # left, bottom, width, height
    cb1 = matplotlib.colorbar.ColorbarBase(ax1, cmap=cm.cool,
                                norm=norm,
                                orientation='vertical')

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        plt.tight_layout()    
In [5]:
filesDir = './'
trainingSetFile = filesDir + 'train-images-idx3-ubyte'
trainingSetLabelsFile = filesDir + 'train-labels-idx1-ubyte'
testSetFile = filesDir + 't10k-images-idx3-ubyte'
testSetLabelsFile = filesDir + 't10k-labels-idx1-ubyte'

trainData = read(fileName=trainingSetFile).astype(np.float64)
trainDataLabels = read(fileName=trainingSetLabelsFile).astype(np.float64)

testData = read(fileName=testSetFile).astype(np.float64)
testDataLabels = read(fileName=testSetLabelsFile).astype(np.float64)
Vector de  3  dimensiones:  (60000, 28, 28)  tipo  <class 'numpy.uint8'>
Vector de  1  dimensiones:  (60000,)  tipo  <class 'numpy.uint8'>
Vector de  3  dimensiones:  (10000, 28, 28)  tipo  <class 'numpy.uint8'>
Vector de  1  dimensiones:  (10000,)  tipo  <class 'numpy.uint8'>

Show all is ok

In [6]:
@interact(index = (0, len(trainData) - 1))
def ShowImageTrain(index):
    muestraImagen(trainData, trainDataLabels, index)
In [7]:
def makeX(data_train):
    num_inputs = data_train.shape[0]
    return torch.FloatTensor(data_train.reshape((num_inputs, 28 * 28)))

def makeY(labels_train):
    num_inputs = labels_train.shape[0]
    return torch.LongTensor(labels_train.reshape((num_inputs, 1)))

X = makeX(trainData)
print("X shape=", X.shape)

Y = makeY(trainDataLabels)
print("Y shape=", Y.shape)
X shape= torch.Size([60000, 784])
Y shape= torch.Size([60000, 1])
In [8]:
## Repite lo mismo con los datos de entrenamiento
XTest = makeX(testData)
YTest = makeY(testDataLabels)
In [9]:
class Network(nn.Module):
    
    def __init__(self, input_size, hidden_size, output_size):
        super(Network, self).__init__()

        self.l1   = nn.Linear(input_size, hidden_size)
        self.bn1  = nn.BatchNorm1d(hidden_size)
        self.relu = nn.Sigmoid()
        self.l3   = nn.Linear(hidden_size, output_size)
        self.bn2  = nn.BatchNorm1d(output_size)
        
    def forward(self, x):
        x = self.l1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.l3(x)
        x = self.bn2(x)
        
        return F.softmax(x, dim=1)
In [10]:
net = Network(input_size=28*28, hidden_size=170, output_size=10)
print(net)
Network(
  (l1): Linear(in_features=784, out_features=170, bias=True)
  (bn1): BatchNorm1d(170, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): Sigmoid()
  (l3): Linear(in_features=170, out_features=10, bias=True)
  (bn2): BatchNorm1d(10, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
In [11]:
optimizer = optim.SGD(net.parameters(), lr=0.005, momentum=0.7)
loss_func = nn.CrossEntropyLoss()
In [12]:
epochs = 45
batch_size = 32

loss_log = []

for e in range(epochs):
    for i in range(0, X.shape[0], batch_size):
        x_mini = X[i:i + batch_size] 
        y_mini = Y[i:i + batch_size] 
        
        x_var = Variable(x_mini)
        y_var = Variable(y_mini)

        optimizer.zero_grad()
        net_out = net(x_var)
        
        loss = loss_func(net_out, y_var[:, 0])
        loss.backward()
        optimizer.step()
        
        if i % 100 == 0:
            loss_log.append(loss.data.item())
    print('Epoch: {} - Loss: {:.6f}'.format(e, loss.data.item()))
Epoch: 0 - Loss: 1.636075
Epoch: 1 - Loss: 1.566639
Epoch: 2 - Loss: 1.544215
Epoch: 3 - Loss: 1.530976
Epoch: 4 - Loss: 1.519311
Epoch: 5 - Loss: 1.508831
Epoch: 6 - Loss: 1.501232
Epoch: 7 - Loss: 1.495354
Epoch: 8 - Loss: 1.488931
Epoch: 9 - Loss: 1.484843
Epoch: 10 - Loss: 1.481362
Epoch: 11 - Loss: 1.479208
Epoch: 12 - Loss: 1.477448
Epoch: 13 - Loss: 1.475488
Epoch: 14 - Loss: 1.474987
Epoch: 15 - Loss: 1.474735
Epoch: 16 - Loss: 1.474152
Epoch: 17 - Loss: 1.473683
Epoch: 18 - Loss: 1.473136
Epoch: 19 - Loss: 1.472183
Epoch: 20 - Loss: 1.471281
Epoch: 21 - Loss: 1.470492
Epoch: 22 - Loss: 1.469171
Epoch: 23 - Loss: 1.467892
Epoch: 24 - Loss: 1.467308
Epoch: 25 - Loss: 1.466670
Epoch: 26 - Loss: 1.466263
Epoch: 27 - Loss: 1.466059
Epoch: 28 - Loss: 1.465983
Epoch: 29 - Loss: 1.465725
Epoch: 30 - Loss: 1.465461
Epoch: 31 - Loss: 1.465237
Epoch: 32 - Loss: 1.464980
Epoch: 33 - Loss: 1.464753
Epoch: 34 - Loss: 1.464702
Epoch: 35 - Loss: 1.464424
Epoch: 36 - Loss: 1.464319
Epoch: 37 - Loss: 1.464409
Epoch: 38 - Loss: 1.464208
Epoch: 39 - Loss: 1.464597
Epoch: 40 - Loss: 1.464138
Epoch: 41 - Loss: 1.464188
Epoch: 42 - Loss: 1.464367
Epoch: 43 - Loss: 1.464643
Epoch: 44 - Loss: 1.464528
In [13]:
def print_proba(ps):
    labels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    plt.bar(labels, ps, align='center', alpha=0.5)
    plt.xticks(labels)
    plt.ylabel('Que tan seguro')
    plt.title('Estimation')

    plt.show()
In [14]:
@interact(index = (0, len(testData) - 1))
def ShowImagePrediction(index):
    muestraImagen(testData, testDataLabels, index)
    data = XTest[index:index+1]
    estimation = net.eval()(data)[0].tolist()
    print_proba(estimation)
In [15]:
matrix_confusion = np.zeros((10, 10),  dtype=int)
correct = 0

total = XTest.shape[0]
for index in range(0, total):
    data = XTest[index:index+1]
    expected = YTest[index].item()
    estimation = net.eval()(data)[0].tolist()
    result = np.argmax(estimation)
    
    matrix_confusion[expected][result] += 1
    
    if int(expected) == int(result):
       correct += 1 
    
print(matrix_confusion)

import seaborn as sns
sns.set()
ax = sns.heatmap(matrix_confusion)

print(f"accuracy = {correct / total}")
[[ 971    1    2    0    0    1    1    1    1    2]
 [   0 1126    2    3    0    0    2    0    2    0]
 [   6    4  978   10    4    2    3   16    9    0]
 [   0    0    2  988    1    7    0    6    3    3]
 [   0    2    2    0  959    0    5    3    1   10]
 [   2    0    0    6    1  874    3    1    3    2]
 [   3    5    0    0    3   16  929    1    1    0]
 [   1    6   10    5    2    2    0  996    2    4]
 [   4    1    2   12    7   20    1    2  917    8]
 [   3    5    2    5    9    5    1   12    6  961]]
accuracy = 0.9699
In [16]:
matrix_confusion = np.zeros((10, 10),  dtype=float)
correct = 0

total = XTest.shape[0]
for index in range(0, total):
    data = XTest[index:index+1]
    expected = YTest[index].item()
    estimation = net(data)[0].tolist()
    result = np.argmax(estimation)
    
    matrix_confusion[expected] += estimation
    
    if int(expected) == int(result):
       correct += 1 
    
print(matrix_confusion.astype(int))

import seaborn as sns
sns.set()
ax = sns.heatmap(matrix_confusion)


print(f"accuracy = {correct / total}")
[[ 965    0    1    0    0    1    2    2    1    2]
 [   0 1123    2    3    0    0    2    0    2    0]
 [   6    5  963   16    4    3    4   14   10    2]
 [   0    0    3  979    0    7    0    6    4    4]
 [   1    2    1    0  952    1    5    2    1   12]
 [   2    1    0    9    1  863    4    2    3    3]
 [   3    4    0    1    4   17  920    1    2    0]
 [   1    8   10    5    2    2    0  987    2    6]
 [   5    4    4   16    6   20    4    5  896    9]
 [   3    6    1    7   11    6    2   12    6  950]]
accuracy = 0.9699
In [17]:
plt.plot(loss_log)
plt.show()