Advertisement
Guest User

Untitled

a guest
Nov 15th, 2019
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.26 KB | None | 0 0
  1. import numpy as np
  2. import pickle
  3. from mlxtend.data import loadlocal_mnist
  4. import math as m
  5. from scipy import signal
  6. import matplotlib.pyplot as plt
  7. import time
  8.  
  9. np.random.seed(1)  # заставим numpy выдавать одинаковые набор случайных чисел для каждого запуска программы
  10. np.set_printoptions(suppress=True)  # выводить числа в формате 0.123 а не 1.23e-1
  11.  
  12. # В `X` находятся изображения для обучения, а в `y` значения соответственно
  13. # `X.shape` == (60000, 784)   # изображения имеют размер 28x28 pix => 28*28=784
  14. # `y.shape` == (60000,)       # каждое значение это число от 0 до 9 то что изображено на соответствующем изображении
  15. X, y = loadlocal_mnist(
  16.     images_path="train-images.idx3-ubyte",
  17.     labels_path="train-labels.idx1-ubyte")
  18.  
  19. # В `Xt` находятся изображения для тестирования, а в `yt` значения соответственно
  20. # `Xt.shape` == (10000, 784)   # изображения имеют размер 28x28 pix => 28*28=784
  21. # `yt.shape` == (10000,)       # каждое значение это число от 0 до 9 то что изображено на соответствующем изображении
  22. Xt, yt = loadlocal_mnist(
  23.     images_path="t10k-images.idx3-ubyte",
  24.     labels_path="t10k-labels.idx1-ubyte")
  25.  
  26.  
  27. def sigmoid(x, deriv=False):
  28.     if deriv:
  29.         return x * (1 - x)
  30.  
  31.     return 1.0 / (1.0 + np.exp(-x))
  32.  
  33.  
  34. def convert(y):
  35.     y_d = np.zeros((len(y), 10))
  36.  
  37.     for idx, val in enumerate(y):
  38.         y_d[idx, val] = 1.0
  39.  
  40.     return y_d
  41.  
  42.  
  43. X = X * (1 / 255)
  44. Xt = Xt * (1 / 255)
  45.  
  46. # Параметры:
  47.  
  48. lr = 1  # значени на которое будет домножаться дельта на каждом шаге
  49. batch = 60  # кол-во изображений использованное для обучения на каждом шаге
  50. epochs = 100  # кол-во эпох. Если видно что прогресс есть, но нужно больше итераций
  51.  
  52.  
  53. class MnistConvModel:
  54.     def __init__(self, lr=0.1, batch=60):
  55.         self.lr = lr
  56.         self.batch = batch
  57.         self.filters = 8
  58.  
  59.         self.W_conv = np.random.uniform(-0.05, 0.05, (self.filters, 3, 3))
  60.         self.W_linear = np.random.uniform(-0.05, 0.05, (self.filters * 26 * 26, 10))
  61.  
  62.     def load(self, conv, linear):
  63.         with open(conv, 'rb') as f:
  64.             self.W_conv = np.array(pickle.load(f)).reshape((self.filters, 3, 3))
  65.  
  66.         with open(linear, 'rb') as f:
  67.             self.W_linear = np.array(pickle.load(f)).reshape((self.filters * 26 * 26, -1))
  68.  
  69.     # Linear Layer
  70.  
  71.     def linear_forward(self, X):
  72.         return np.dot(X, self.W_linear)
  73.  
  74.     def linear_backward(self, e):
  75.         return np.dot(e, self.W_linear.T)
  76.  
  77.     # Sigmoid Layer
  78.  
  79.     def sigmoid_forward(self, X):
  80.         return sigmoid(X)
  81.  
  82.     def sigmoid_backward(self, e):
  83.         return e * sigmoid(self.o_sigmoid, True)
  84.  
  85.     # ReLU Layer
  86.  
  87.     def relu_forward(self, X):
  88.  
  89.        #print("reLuForward: ", X.shape)
  90.         X_o = X.copy()
  91.         X_o[X < 0] = 0
  92.  
  93.         return X_o
  94.  
  95.     def relu_backward(self, s):
  96.         res = s.copy()
  97.         res[res > 0] = 1.0
  98.  
  99.         return res
  100.  
  101.     # Convolution Layer
  102.  
  103.     def convolution_forward(self, X):
  104.         (filter_channels, filter_height, filter_width) = self.W_conv.shape
  105.         (batch_size, in_channels, in_rows, in_cols) = X.shape
  106.         (out_channels, out_rows, out_cols) = (filter_channels, in_rows - 2, in_cols - 2)
  107.  
  108.         res = np.zeros((batch_size, out_channels, out_rows, out_cols))
  109.  
  110.         for batch in range(0, batch_size):
  111.             for och in range(0, out_channels):
  112.                 for ich in range(0, in_channels):
  113.                     res[batch][och] += signal.convolve2d(X[batch][ich], self.W_conv[och], mode='valid')
  114.         #print(res.shape)
  115.         return res
  116.  
  117.     def convolution_backward(self, e):
  118.  
  119.         (filter_channels, filter_height, filter_width) = self.W_conv.shape
  120.         (batch_size, out_channels, out_rows, out_cols) = e.shape
  121.         (in_channels, in_rows, in_cols) = (1, out_rows + 2, out_cols + 2)
  122.         res = np.zeros((batch_size, in_channels, in_rows, in_cols))
  123.         for batch in range(0, batch_size):
  124.             for ich in range(0, in_channels):
  125.                 for och in range(0, out_channels):
  126.                     res[batch][0] += signal.convolve2d(e[batch][och], self.W_conv[och], mode='full')
  127.  
  128.         #print(res.shape)
  129.         res = res / len(e) / 8
  130.         return res
  131.  
  132.     def forward(self, X):
  133.  
  134.         self.X = X
  135.         self.o_conv = self.convolution_forward(X)
  136.         self.o_relu = self.relu_forward(self.o_conv).reshape(len(X), -1)
  137.         self.o_linear = self.linear_forward(self.o_relu)
  138.         self.o_sigmoid = self.sigmoid_forward(self.o_linear)
  139.         return self.o_sigmoid
  140.  
  141.     def backward(self, e):
  142.         self.e_sigmoid = self.sigmoid_backward(e)
  143.         self.e_linear = self.linear_backward(self.e_sigmoid)
  144.         self.e_relu = self.relu_backward(self.e_linear.reshape((-1, self.filters, 26, 26)))
  145.         self.e_conv = self.convolution_backward(self.e_relu)
  146.     def calc_gradients(self):
  147.         scaler = 1 / len(self.X)
  148.         # print(self.o_relu.T.shape)
  149.         # print(self.e_sigmoid.shape)
  150.         self.dW_linear = np.dot(self.o_relu.T, self.e_sigmoid) * scaler
  151.  
  152.  
  153.  
  154.  
  155.         #print( self.e_conv.shape)
  156.  
  157.  
  158.         (batch_size, out_channels, out_rows, out_cols) = self.e_conv.shape
  159.         (in_channels, in_rows, in_cols) = (1, out_rows + 2, out_cols + 2)
  160.        # res = np.zeros((batch_size, out_channels, in_rows, in_cols))
  161.  
  162.         # for batch in range(0, batch_size):
  163.         #         for och in range(0, out_channels):
  164.         #
  165.         #             res[batch][och] += signal.convolve2d( self.e_relu[batch][och], self.W_conv[och], mode='full')
  166.         # print(self.X[batch][0].shape)
  167.         # print(res[batch][och].shape)
  168.  
  169.         temp = np.zeros(self.W_conv.shape)
  170.         #print()
  171.         for batch in range(0, batch_size):
  172.             for och in range(0, out_channels):
  173.                 # print(res[batch][och].shape)
  174.                 # print(self.e_relu[batch][och].shape)
  175.                 # print()
  176.                 temp[och] += signal.convolve2d(self.e_conv[batch][0], self.e_relu[batch][och], mode='valid')
  177.         #print(self.dW_conv == temp)
  178.         self.dW_conv = temp * scaler
  179.  
  180.     def update(self):
  181.         self.W_linear -= self.dW_linear * self.lr
  182.         self.W_conv -= self.dW_conv * self.lr
  183.  
  184.  
  185. def mse(o, y):
  186.     return np.sum(np.square(o - y))
  187.  
  188.  
  189. def mse_prime(o, y):
  190.     return 2 * (o - y)
  191.  
  192.  
  193. def validate(model, X, y):
  194.     tp = model.forward(X)
  195.  
  196.     return np.sum(y == np.argmax(tp, axis=1)) / len(y)
  197.  
  198.  
  199. def train(model, X, y, epochs=100, batch_size=100, validation=None):
  200.     batch_count = m.ceil(len(y) / batch_size)
  201.     #print( batch_count)
  202.     t = np.zeros((len(y), 10))
  203.     np.put_along_axis(t, y.reshape((-1, 1)), 1.0, axis=1)
  204.     losses = np.zeros((epochs * 6))
  205.     lindex = 0
  206.     for epoch in range(0, epochs):
  207.         print("Epoch ", epoch + 1)
  208.         st_t = time.time()
  209.         for index, (bX, bt) in enumerate(zip(np.split(X, batch_count), np.split(t, batch_count))):
  210.            # print(bX.shape)
  211.             res = model.forward(bX)
  212.             error = mse_prime(res, bt)
  213.  
  214.             model.backward(error)
  215.             model.calc_gradients()
  216.             model.update()
  217.  
  218.             if index % 100 == 0:
  219.                 losses[lindex] = mse(res, bt)
  220.                 print("  Loss: ", losses[lindex])
  221.                 lindex += 1
  222.  
  223.         if validation is not None:
  224.             end_t = time.time()
  225.             (model, val_X, val_y) = validation
  226.             print("  Accuracy: ", validate(model, val_X, val_y))
  227.  
  228.     plt.title("Loss функция")
  229.     plt.xlabel('')
  230.     plt.ylabel('loss')
  231.     plt.grid()
  232.     plt.plot(np.arange(epochs * 6), losses)
  233.     plt.show()
  234. if __name__ == "__main__":
  235.     model = MnistConvModel()
  236.     X = X.reshape((-1, 1, 28, 28))
  237.     Xt = Xt.reshape((-1, 1, 28, 28))
  238.  
  239.     train(model, X, y, epochs=10, validation=(model, Xt, yt))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement