Машинное обучение 101 Все алгоритмы в питоне (нейронная сеть прямого и обратного распространения с нуля)
Делаем задания профессора Эндрю на популярном курсе машинного обучения Coursera на Python.
В этом блоге я расскажу вам о выполнении самых популярных заданий курса машинного обучения, доступных в Интернете, представленных профессором Эндрю Нг. Мы собираемся построить алгоритм нейронной сети с нуля для выполнения мультиклассовой классификации.
Если вы не читали мои предыдущие блоги о машинном обучении 101, вы можете прочитать их здесь.
Введение
В этом блоге мы реализуем алгоритм обратного распространения ошибки для нейронных сетей и применим его к задаче распознавания рукописных цифр. Прежде чем приступить к упражнению по программированию, мы настоятельно рекомендуем посмотреть видеолекции и ответить на контрольные вопросы по соответствующим темам.
Прежде чем мы начнем с блога, нам нужно импортировать все библиотеки, необходимые для этого упражнения по программированию. На протяжении всего курса мы будем использовать numpy
для всех операций с массивами и матрицами, matplotlib
для построения графиков и scipy
для функций и инструментов научных и числовых вычислений.
Импорт пакетов Python
# used for manipulating directory paths import os # Scientific and vector computation for python import numpy as np # Plotting library from matplotlib import pyplot # Optimization module in scipy from scipy import optimize # will be used to load MATLAB mat datafile format from scipy.io import loadmat # library written for this exercise providing additional functions for assignment submission, and others import utils # tells matplotlib to embed plots within the notebook %matplotlib inline
Нейронные сети
В предыдущем блоге мы внедрили упреждающее распространение для нейронных сетей и использовали его для предсказания рукописных цифр с предоставленными нами весами. В этом блоге мы реализуем алгоритм обратного распространения, чтобы узнать параметры нейронной сети.
загрузка набора данных
# training data stored in arrays X, y data = loadmat(os.path.join('Data', 'ex4data1.mat')) X, y = data['X'], data['y'].ravel() # set the zero digit to 0, rather than its mapped 10 in this dataset # This is an artifact due to the fact that this dataset was used in # MATLAB where there is no index 0 y[y == 10] = 0 # Number of training examples m = y.size
Визуализация данных
Мы начнем с визуализации подмножества обучающего набора, используя функцию displayData
, ту же функцию, которую мы использовали в предыдущем блоге. Он также содержится в файле utils.py
для этого задания. Набор данных тот же, что вы использовали в предыдущем блоге.
Проверьте этот репозиторий GitHub, чтобы найти используемый набор данных и блокнот Jupyter.
В ex4data1.mat
есть 5000 обучающих примеров, где каждый обучающий пример представляет собой изображение цифры в градациях серого размером 20 на 20 пикселей. Каждый пиксель представлен числом с плавающей запятой, указывающим интенсивность оттенков серого в этом месте. Сетка пикселей 20 на 20 «разворачивается» в 400-мерный вектор. Каждый из этих обучающих примеров становится отдельной строкой в нашей матрице данных X. Это дает нам матрицу 5000 на 400 X, где каждая строка является обучающим примером для изображения рукописной цифры.
Вторая часть обучающего набора — это 5000-мерный вектор y
, который содержит метки для обучающего набора. Следующая ячейка случайным образом выбирает 100 изображений из набора данных и отображает их.
# Randomly select 100 data points to display rand_indices = np.random.choice(m, 100, replace=False) sel = X[rand_indices, :] utils.displayData(sel)
Представление модели
Наша нейронная сеть показана на следующем рисунке.
Он имеет 3 слоя — входной слой, скрытый слой и выходной слой. Напомним, что наши входные данные представляют собой значения пикселей цифровых изображений. Поскольку изображения имеют размер 20 x 20, это дает нам 400 единиц входного слоя (не считая дополнительной единицы смещения, которая всегда выводит +1). Данные обучения были загружены в переменные X
и y
выше.
Вам предоставлен уже обученный нами набор сетевых параметров Theta_1, Theta_2. Они хранятся в ex4weights.mat
и будут загружены в следующую ячейку этой записной книжки в Theta1
и Theta2
. Параметры имеют размеры, соответствующие размеру нейронной сети с 25 единицами во втором слое и 10 единицами вывода (соответствующими 10-значным классам).
# Setup the parameters you will use for this exercise input_layer_size = 400 # 20x20 Input Images of Digits hidden_layer_size = 25 # 25 hidden units num_labels = 10 # 10 labels, from 0 to 9 # Load the weights into variables Theta1 and Theta2 weights = loadmat(os.path.join('Data', 'ex4weights.mat')) # Theta1 has size 25 x 401 # Theta2 has size 10 x 26 Theta1, Theta2 = weights['Theta1'], weights['Theta2'] # swap first and last columns of Theta2, due to legacy from MATLAB indexing, # since the weight file ex3weights.mat was saved based on MATLAB indexing Theta2 = np.roll(Theta2, 1, axis=0) # Unroll parameters nn_params = np.concatenate([Theta1.ravel(), Theta2.ravel()])
Функция прямой связи и стоимости
Теперь мы реализуем функцию стоимости и градиент для нейронной сети. Во-первых, функция nnCostFunction
в следующей ячейке возвращает стоимость.
Напомним, что функция стоимости для нейронной сети (без регуляризации):
где h(theta)(Xi) вычисляется, как показано на рисунке нейронной сети выше, а K = 10 — это общее количество возможных меток. Обратите внимание, что h(theta)(Xi) k =3 – это активация (выходное значение) k-го блока вывода. Также напомню, что хотя исходные метки (в переменной y) были 0, 1, …, 9, для обучения нейронной сети нам нужно закодировать метки как векторы, содержащие только значения 0 или 1, так что
Например, если Xi — это изображение цифры 5, то соответствующий Yi (который следует использовать с функцией стоимости) должен быть 10-мерным вектором. с y[5] = 1, а остальные элементы равны 0.
Мы должны реализовать вычисление с прямой связью, которое вычисляет h(theta)(Xi) для каждого примера i и суммирует стоимость по всем примерам. Код также должен работать для набора данных любого размера с любым количеством меток.
def sigmoid(z): """ Compute sigmoid function given the input z. Parameters ---------- z : array_like The input to the sigmoid function. This can be a 1-D vector or a 2-D matrix. Returns ------- g : array_like The computed sigmoid function. g has the same shape as z, since the sigmoid is computed element-wise on z. Instructions ------------ Compute the sigmoid of each value of z (z can be a matrix, vector or scalar). """ # convert input to a numpy array z = np.array(z) # You need to return the following variables correctly g = np.zeros(z.shape) g=1/(1+np.exp(-z)) return g def nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_=0.0): """ Implements the neural network cost function and gradient for a two layer neural network which performs classification. Parameters ---------- nn_params : array_like The parameters for the neural network which are "unrolled" into a vector. This needs to be converted back into the weight matrices Theta1 and Theta2. input_layer_size : int Number of features for the input layer. hidden_layer_size : int Number of hidden units in the second layer. num_labels : int Total number of labels, or equivalently number of units in output layer. X : array_like Input dataset. A matrix of shape (m x input_layer_size). y : array_like Dataset labels. A vector of shape (m,). lambda_ : float, optional Regularization parameter. Returns ------- J : float The computed value for the cost function at the current weight values. grad : array_like An "unrolled" vector of the partial derivatives of the concatenatation of neural network weights Theta1 and Theta2. Instructions ------------ You should complete the code by working through the following parts. - Part 1: Feedforward the neural network and return the cost in the variable J. After implementing Part 1, you can verify that your cost function computation is correct by verifying the cost computed in the following cell. - Part 2: Implement the backpropagation algorithm to compute the gradients Theta1_grad and Theta2_grad. You should return the partial derivatives of the cost function with respect to Theta1 and Theta2 in Theta1_grad and Theta2_grad, respectively. After implementing Part 2, you can check that your implementation is correct by running checkNNGradients provided in the utils.py module. Note: The vector y passed into the function is a vector of labels containing values from 0..K-1. You need to map this vector into a binary vector of 1's and 0's to be used with the neural network cost function. Hint: We recommend implementing backpropagation using a for-loop over the training examples if you are implementing it for the first time. - Part 3: Implement regularization with the cost function and gradients. Hint: You can implement this around the code for backpropagation. That is, you can compute the gradients for the regularization separately and then add them to Theta1_grad and Theta2_grad from Part 2. Note ---- We have provided an implementation for the sigmoid function in the file `utils.py` accompanying this assignment. """ # Reshape nn_params back into the parameters Theta1 and Theta2, the weight matrices # for our 2 layer neural network Theta1 = np.reshape(nn_params[:hidden_layer_size * (input_layer_size + 1)], (hidden_layer_size, (input_layer_size + 1))) Theta2 = np.reshape(nn_params[(hidden_layer_size * (input_layer_size + 1)):], (num_labels, (hidden_layer_size + 1))) # Encoding the labels to be instead of 0,1,2....9, [0,1,0,0,0,0,0,0,0,0] m = y.size y_new = np.zeros((m, num_labels)) for i in range(m): y_new[i,y[i]] = 1 # You need to return the following variables correctly J = 0 Theta1_grad = np.zeros(Theta1.shape) Theta2_grad = np.zeros(Theta2.shape) # Part 1: Feedforward the neural network and return the cost in the variable J X = np.concatenate([np.ones((m, 1)), X], axis=1) a_1 = X a_2 = sigmoid(np.dot(a_1,Theta1.T)) a_2 = np.concatenate([np.ones((a_2.shape[0], 1)), a_2], axis=1) ho = sigmoid(np.dot(a_2,Theta2.T)) J = (1/m)*(np.sum (np.sum( ((-y_new*np.log(ho))-((1-y_new)*np.log(1-ho))),axis=1))) return J, grad
как только вы закончите, вызовите nnCostFunction
, используя загруженный набор параметров для Theta1
и Theta2
. Вы должны увидеть, что стоимость составляет около 0,287629.
lambda_ = 0 J, _ = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_) print('Cost at parameters (loaded from ex4weights): %.6f ' % J) print('The cost should be
Вывод
Cost at parameters (loaded from ex4weights): 0.287629 The cost should be about : 0.287629.
Регулярная функция затрат
Функция стоимости для нейронных сетей с регуляризацией определяется следующим образом:
можно предположить, что нейронная сеть будет иметь только 3 слоя — входной слой, скрытый слой и выходной слой. Однако код должен работать для любого количества входных, скрытых и выходных единиц. Хотя мы явно перечислили индексы выше для Theta_1 и Theta_2 для ясности, обратите внимание, что код в целом должен работать с Theta_1 и Theta_2 любого размера. Обратите внимание, что вы не должны упорядочивать термины, соответствующие предвзятости. Для матриц Theta1
и Theta2
это соответствует первому столбцу каждой матрицы. Теперь вы должны добавить регуляризацию к вашей функции стоимости. Обратите внимание, что вы можете сначала вычислить функцию нерегулярных затрат J, используя существующую nnCostFunction
, а затем добавить стоимость для условий регуляризации.
Вернемся к nnCostFunction
для редактирования.
Как только вы закончите, следующая ячейка вызовет ваш nnCostFunction
, используя загруженный набор параметров для Theta1
и Theta2
, а лямбда = 1. Вы должны увидеть, что стоимость составляет около 0,383770.
def nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_=0.0): """ Implements the neural network cost function and gradient for a two layer neural network which performs classification. Parameters ---------- nn_params : array_like The parameters for the neural network which are "unrolled" into a vector. This needs to be converted back into the weight matrices Theta1 and Theta2. input_layer_size : int Number of features for the input layer. hidden_layer_size : int Number of hidden units in the second layer. num_labels : int Total number of labels, or equivalently number of units in output layer. X : array_like Input dataset. A matrix of shape (m x input_layer_size). y : array_like Dataset labels. A vector of shape (m,). lambda_ : float, optional Regularization parameter. Returns ------- J : float The computed value for the cost function at the current weight values. grad : array_like An "unrolled" vector of the partial derivatives of the concatenatation of neural network weights Theta1 and Theta2. Instructions ------------ You should complete the code by working through the following parts. - Part 1: Feedforward the neural network and return the cost in the variable J. After implementing Part 1, you can verify that your cost function computation is correct by verifying the cost computed in the following cell. - Part 2: Implement the backpropagation algorithm to compute the gradients Theta1_grad and Theta2_grad. You should return the partial derivatives of the cost function with respect to Theta1 and Theta2 in Theta1_grad and Theta2_grad, respectively. After implementing Part 2, you can check that your implementation is correct by running checkNNGradients provided in the utils.py module. Note: The vector y passed into the function is a vector of labels containing values from 0..K-1. You need to map this vector into a binary vector of 1's and 0's to be used with the neural network cost function. Hint: We recommend implementing backpropagation using a for-loop over the training examples if you are implementing it for the first time. - Part 3: Implement regularization with the cost function and gradients. Hint: You can implement this around the code for backpropagation. That is, you can compute the gradients for the regularization separately and then add them to Theta1_grad and Theta2_grad from Part 2. Note ---- We have provided an implementation for the sigmoid function in the file `utils.py` accompanying this assignment. """ # Reshape nn_params back into the parameters Theta1 and Theta2, the weight matrices # for our 2 layer neural network Theta1 = np.reshape(nn_params[:hidden_layer_size * (input_layer_size + 1)], (hidden_layer_size, (input_layer_size + 1))) Theta2 = np.reshape(nn_params[(hidden_layer_size * (input_layer_size + 1)):], (num_labels, (hidden_layer_size + 1))) # Encoding the labels to be instead of 0,1,2....9, [0,1,0,0,0,0,0,0,0,0] m = y.size y_new = np.zeros((m, num_labels)) for i in range(m): y_new[i,y[i]] = 1 # You need to return the following variables correctly J = 0 Theta1_grad = np.zeros(Theta1.shape) Theta2_grad = np.zeros(Theta2.shape) # Part 1: Feedforward the neural network and return the cost in the variable J X = np.concatenate([np.ones((m, 1)), X], axis=1) a_1 = X a_2 = sigmoid(np.dot(a_1,Theta1.T)) a_2 = np.concatenate([np.ones((a_2.shape[0], 1)), a_2], axis=1) ho = sigmoid(np.dot(a_2,Theta2.T)) regularized_term = (lambda_/(2*m))*((np.sum(np.sum(Theta1[:,1:]**2,axis=1)))+(np.sum(np.sum(Theta2[:,1:]**2,axis=1)))) J = (1/m)*(np.sum (np.sum( ((-y_new*np.log(ho))-((1-y_new)*np.log(1-ho))),axis=1)))+regularized_term return J, grad # Weight regularization parameter (we set this to 1 here). lambda_ = 1 J, _ = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_) print('Cost at parameters (loaded from ex4weights): %.6f' % J) print('This value should be about : 0.383770.')
Вывод
Cost at parameters (loaded from ex4weights): 0.383770 This value should be about : 0.383770.
Если вы до сих пор следите за новостями, отличная работа
Обратное распространение
В этой части упражнения мы реализуем алгоритм обратного распространения ошибки для вычисления градиента функции стоимости нейронной сети. нам нужно будет обновить функцию nnCostFunction
, чтобы она возвращала соответствующее значение для grad
. Как только мы вычислим градиент, мы сможем обучить нейронную сеть, минимизируя функцию стоимости J (тета) с помощью продвинутого оптимизатора, такого как scipy
optimize.minimize
. сначала мы реализуем алгоритм обратного распространения для вычисления градиентов параметров для (нерегулярной) нейронной сети. После того, как мы убедились, что вычисление градиента для нерегуляризованного случая корректно, мы реализуем градиент для регуляризованной нейронной сети.
Сигмовидный градиент
Чтобы помочь вам приступить к этой части упражнения, мы сначала реализуем функцию сигмовидного градиента. Градиент для сигмовидной функции можно вычислить как:
def sigmoidGradient(z): """ Computes the gradient of the sigmoid function evaluated at z. This should work regardless if z is a matrix or a vector. In particular, if z is a vector or matrix, you should return the gradient for each element. Parameters ---------- z : array_like A vector or matrix as input to the sigmoid function. Returns -------- g : array_like Gradient of the sigmoid function. Has the same shape as z. Instructions ------------ Compute the gradient of the sigmoid function evaluated at each value of z (z can be a matrix, vector or scalar). Note ---- We have provided an implementation of the sigmoid function in `utils.py` file accompanying this assignment. """ g = np.zeros(z.shape) # ====================== YOUR CODE HERE ====================== g=(sigmoid(z)*(1-sigmoid(z))) # ============================================================= return g
Когда мы закончим, следующая ячейка вызовет sigmoidGradient
для заданного вектора z
. Попробуйте проверить несколько значений, вызвав sigmoidGradient(z)
. Для больших значений (как положительных, так и отрицательных) z градиент должен быть близок к 0. Когда z = 0, градиент должен быть ровно 0,25. код также должен работать с векторами и матрицами. Для матрицы функция должна выполнять функцию сигмовидного градиента для каждого элемента.
z = np.array([-1, -0.5, 0, 0.5, 1]) g = sigmoidGradient(z) print('Sigmoid gradient evaluated at [-1 -0.5 0 0.5 1]:\n ') print(g)
Вывод
Sigmoid gradient evaluated at [-1 -0.5 0 0.5 1]: [0.19661193 0.23500371 0.25 0.23500371 0.19661193]
Случайная инициализация
При обучении нейронных сетей важно случайным образом инициализировать параметры для нарушения симметрии. Одной из эффективных стратегий случайной инициализации является случайный выбор значений для Theta_1 равномерно в диапазоне [-эпсилон, эпсилон]. Вы должны использовать эпсилон = 0,12$. Этот диапазон значений гарантирует, что параметры остаются небольшими, и делает обучение более эффективным.
def randInitializeWeights(L_in, L_out, epsilon_init=0.12): """ Randomly initialize the weights of a layer in a neural network. Parameters ---------- L_in : int Number of incomming connections. L_out : int Number of outgoing connections. epsilon_init : float, optional Range of values which the weight can take from a uniform distribution. Returns ------- W : array_like The weight initialiatized to random values. Note that W should be set to a matrix of size(L_out, 1 + L_in) as the first column of W handles the "bias" terms. Instructions ------------ Initialize W randomly so that we break the symmetry while training the neural network. Note that the first column of W corresponds to the parameters for the bias unit. """ # You need to return the following variables correctly W = np.zeros((L_out, 1 + L_in)) # ====================== YOUR CODE HERE ====================== W = np.random.rand(L_out, 1 + L_in) * 2 * epsilon_init - epsilon_init # ============================================================ return W
Выполните следующую ячейку, чтобы инициализировать веса для двух слоев нейронной сети с помощью функции randInitializeWeights
.
print('Initializing Neural Network Parameters ...') initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size) initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels) # Unroll parameters initial_nn_params = np.concatenate([initial_Theta1.ravel(), initial_Theta2.ravel()], axis=0)
Обратное распространение
Теперь вы реализуете алгоритм обратного распространения. Напомним, что интуиция, стоящая за алгоритмом обратного распространения ошибки, такова. Учитывая обучающий пример (x, y), мы сначала запустим «прямой проход», чтобы вычислить все активации по всей сети, включая выходное значение гипотезы h (тета). Затем для каждого узла j в слое L мы хотели бы вычислить «дельта члена ошибки [j]^[L], которая измеряет, насколько этот узел был «ответственным». ” для любых ошибок в нашем выводе.
Для выходного узла мы можем напрямую измерить разницу между активацией сети и истинным целевым значением и использовать это для определения delta_3. Для скрытых единиц вы вычислите delta_2 на основе средневзвешенного значения ошибок узлов в слое (l+1). Подробно, вот алгоритм обратного распространения (также изображен на рисунке выше). Вы должны реализовать шаги с 1 по 4 в цикле, который обрабатывает один пример за раз. Конкретно, вы должны реализовать цикл for for t in range(m)
и поместить шаги 1-4 ниже внутри цикла for.
def nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_=0.0): """ Implements the neural network cost function and gradient for a two layer neural network which performs classification. Parameters ---------- nn_params : array_like The parameters for the neural network which are "unrolled" into a vector. This needs to be converted back into the weight matrices Theta1 and Theta2. input_layer_size : int Number of features for the input layer. hidden_layer_size : int Number of hidden units in the second layer. num_labels : int Total number of labels, or equivalently number of units in output layer. X : array_like Input dataset. A matrix of shape (m x input_layer_size). y : array_like Dataset labels. A vector of shape (m,). lambda_ : float, optional Regularization parameter. Returns ------- J : float The computed value for the cost function at the current weight values. grad : array_like An "unrolled" vector of the partial derivatives of the concatenatation of neural network weights Theta1 and Theta2. Instructions ------------ You should complete the code by working through the following parts. - Part 1: Feedforward the neural network and return the cost in the variable J. After implementing Part 1, you can verify that your cost function computation is correct by verifying the cost computed in the following cell. - Part 2: Implement the backpropagation algorithm to compute the gradients Theta1_grad and Theta2_grad. You should return the partial derivatives of the cost function with respect to Theta1 and Theta2 in Theta1_grad and Theta2_grad, respectively. After implementing Part 2, you can check that your implementation is correct by running checkNNGradients provided in the utils.py module. Note: The vector y passed into the function is a vector of labels containing values from 0..K-1. You need to map this vector into a binary vector of 1's and 0's to be used with the neural network cost function. Hint: We recommend implementing backpropagation using a for-loop over the training examples if you are implementing it for the first time. - Part 3: Implement regularization with the cost function and gradients. Hint: You can implement this around the code for backpropagation. That is, you can compute the gradients for the regularization separately and then add them to Theta1_grad and Theta2_grad from Part 2. Note ---- We have provided an implementation for the sigmoid function in the file `utils.py` accompanying this assignment. """ # Reshape nn_params back into the parameters Theta1 and Theta2, the weight matrices # for our 2 layer neural network Theta1 = np.reshape(nn_params[:hidden_layer_size * (input_layer_size + 1)], (hidden_layer_size, (input_layer_size + 1))) Theta2 = np.reshape(nn_params[(hidden_layer_size * (input_layer_size + 1)):], (num_labels, (hidden_layer_size + 1))) # Encoding the labels to be instead of 0,1,2....9, [0,1,0,0,0,0,0,0,0,0] m = y.size y_new = np.zeros((m, num_labels)) for i in range(m): y_new[i,y[i]] = 1 # You need to return the following variables correctly J = 0 Theta1_grad = np.zeros(Theta1.shape) Theta2_grad = np.zeros(Theta2.shape) # Part 1: Feedforward the neural network and return the cost in the variable J X = np.concatenate([np.ones((m, 1)), X], axis=1) a_1 = X a_2 = sigmoid(np.dot(a_1,Theta1.T)) a_2 = np.concatenate([np.ones((a_2.shape[0], 1)), a_2], axis=1) ho = sigmoid(np.dot(a_2,Theta2.T)) regularized_term = (lambda_/(2*m))*((np.sum(np.sum(Theta1[:,1:]**2,axis=1)))+(np.sum(np.sum(Theta2[:,1:]**2,axis=1)))) J = (1/m)*(np.sum (np.sum( ((-y_new*np.log(ho))-((1-y_new)*np.log(1-ho))),axis=1)))+regularized_term # - Part 2: Implement the backpropagation algorithm to compute the gradients for i in range(m): a1 = X[[i]] # (1,401) z2 = np.dot(Theta1,a1.T) # (25,401)(401,1) = (25,1) a2 = sigmoid(z2) # (25,1) a2 = np.concatenate([np.ones([1,1]),a2]) # (26,1) z3 = np.dot(Theta2,a2) # (10,26)(26,1)= (10,1) a3 = sigmoid(z3) # (10,1) delta3 = a3-y_new[[i]].T # (10,1) z2 = np.concatenate([np.ones([1,1]),z2]) # (26,1) delta2 = np.dot(Theta2.T,delta3)*sigmoidGradient(z2) # (26,10)(10,1) = (26,1) delta2 = delta2[1:,:] # (25,1) Theta1_grad = Theta1_grad+np.dot(delta2,a1) # ((25,1)(1,401)) = (25,401) Theta2_grad = Theta2_grad+np.dot(delta3,a2.T) # (10,1)(1,26)= (10,26) # Unroll gradients grad = np.concatenate([Theta1_grad.ravel(), Theta2_grad.ravel()]) return J, grad
Регулярная нейронная сеть
После того, как вы успешно реализовали алгоритм обратного распространения, вы добавите регуляризацию в градиент. Оказывается, чтобы учесть регуляризацию, вы можете добавить это как дополнительный термин после вычисления градиентов с использованием обратного распространения ошибки.
Вы должны добавить регуляризацию, используя
def nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_=0.0): """ Implements the neural network cost function and gradient for a two layer neural network which performs classification. Parameters ---------- nn_params : array_like The parameters for the neural network which are "unrolled" into a vector. This needs to be converted back into the weight matrices Theta1 and Theta2. input_layer_size : int Number of features for the input layer. hidden_layer_size : int Number of hidden units in the second layer. num_labels : int Total number of labels, or equivalently number of units in output layer. X : array_like Input dataset. A matrix of shape (m x input_layer_size). y : array_like Dataset labels. A vector of shape (m,). lambda_ : float, optional Regularization parameter. Returns ------- J : float The computed value for the cost function at the current weight values. grad : array_like An "unrolled" vector of the partial derivatives of the concatenatation of neural network weights Theta1 and Theta2. Instructions ------------ You should complete the code by working through the following parts. - Part 1: Feedforward the neural network and return the cost in the variable J. After implementing Part 1, you can verify that your cost function computation is correct by verifying the cost computed in the following cell. - Part 2: Implement the backpropagation algorithm to compute the gradients Theta1_grad and Theta2_grad. You should return the partial derivatives of the cost function with respect to Theta1 and Theta2 in Theta1_grad and Theta2_grad, respectively. After implementing Part 2, you can check that your implementation is correct by running checkNNGradients provided in the utils.py module. Note: The vector y passed into the function is a vector of labels containing values from 0..K-1. You need to map this vector into a binary vector of 1's and 0's to be used with the neural network cost function. Hint: We recommend implementing backpropagation using a for-loop over the training examples if you are implementing it for the first time. - Part 3: Implement regularization with the cost function and gradients. Hint: You can implement this around the code for backpropagation. That is, you can compute the gradients for the regularization separately and then add them to Theta1_grad and Theta2_grad from Part 2. Note ---- We have provided an implementation for the sigmoid function in the file `utils.py` accompanying this assignment. """ # Reshape nn_params back into the parameters Theta1 and Theta2, the weight matrices # for our 2 layer neural network Theta1 = np.reshape(nn_params[:hidden_layer_size * (input_layer_size + 1)], (hidden_layer_size, (input_layer_size + 1))) Theta2 = np.reshape(nn_params[(hidden_layer_size * (input_layer_size + 1)):], (num_labels, (hidden_layer_size + 1))) # Encoding the labels to be instead of 0,1,2....9, [0,1,0,0,0,0,0,0,0,0] m = y.size y_new = np.zeros((m, num_labels)) for i in range(m): y_new[i,y[i]] = 1 # You need to return the following variables correctly J = 0 Theta1_grad = np.zeros(Theta1.shape) Theta2_grad = np.zeros(Theta2.shape) # Part 1: Feedforward the neural network and return the cost in the variable J X = np.concatenate([np.ones((m, 1)), X], axis=1) a_1 = X a_2 = sigmoid(np.dot(a_1,Theta1.T)) a_2 = np.concatenate([np.ones((a_2.shape[0], 1)), a_2], axis=1) ho = sigmoid(np.dot(a_2,Theta2.T)) regularized_term = (lambda_/(2*m))*((np.sum(np.sum(Theta1[:,1:]**2,axis=1)))+(np.sum(np.sum(Theta2[:,1:]**2,axis=1)))) J = (1/m)*(np.sum (np.sum( ((-y_new*np.log(ho))-((1-y_new)*np.log(1-ho))),axis=1)))+regularized_term # - Part 2: Implement the backpropagation algorithm to compute the gradients for i in range(m): a1 = X[[i]] # (1,401) z2 = np.dot(Theta1,a1.T) # (25,401)(401,1) = (25,1) a2 = sigmoid(z2) # (25,1) a2 = np.concatenate([np.ones([1,1]),a2]) # (26,1) z3 = np.dot(Theta2,a2) # (10,26)(26,1)= (10,1) a3 = sigmoid(z3) # (10,1) delta3 = a3-y_new[[i]].T # (10,1) z2 = np.concatenate([np.ones([1,1]),z2]) # (26,1) delta2 = np.dot(Theta2.T,delta3)*sigmoidGradient(z2) # (26,10)(10,1) = (26,1) delta2 = delta2[1:,:] # (25,1) Theta1_grad = Theta1_grad+np.dot(delta2,a1) # ((25,1)(1,401)) = (25,401) Theta2_grad = Theta2_grad+np.dot(delta3,a2.T) # (10,1)(1,26)= (10,26) # - Part 3: Implement regularization with the cost function and gradients. Theta2_grad[:, 0] = (1/m) * Theta2_grad[:, 0] Theta2_grad[:, 1:] = (1/m) * Theta2_grad[:, 1:]+((lambda_/m) * Theta2_grad[:, 1:]) Theta1_grad[:, 0] = (1/m) * Theta1_grad[:, 0] # (10*26) Theta1_grad[:, 1:] = (1/m) * Theta1_grad[:, 1:]+((lambda_/m) * Theta1_grad[:, 1:]) # Unroll gradients grad = np.concatenate([Theta1_grad.ravel(), Theta2_grad.ravel()]) return J, grad
Обучение параметрам с использованием scipy.optimize.minimize
После того, как вы успешно реализовали функцию стоимости нейронной сети и вычисление градиента, на следующем шаге мы будем использовать минимизацию scipy
, чтобы изучить хороший набор параметров.
# After you have completed the assignment, change the maxiter to a larger # value to see how more training helps. options= {'maxiter': 100} # You should also try different values of lambda lambda_ = 1 # Create "short hand" for the cost function to be minimized costFunction = lambda p: nnCostFunction(p, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_) # Now, costFunction is a function that takes in only one argument # (the neural network parameters) res = optimize.minimize(costFunction, initial_nn_params, jac=True, method='TNC', options=options) # get the solution of the optimization nn_params = res.x # Obtain Theta1 and Theta2 back from nn_params Theta1 = np.reshape(nn_params[:hidden_layer_size * (input_layer_size + 1)], (hidden_layer_size, (input_layer_size + 1))) Theta2 = np.reshape(nn_params[(hidden_layer_size * (input_layer_size + 1)):], (num_labels, (hidden_layer_size + 1)))
После завершения обучения мы сообщим о точности обучения вашего классификатора, рассчитав процент правильных примеров. Если ваша реализация правильная, вы должны увидеть заявленную точность обучения около 95,3% (это может варьироваться примерно на 1% из-за случайной инициализации). Можно повысить точность обучения, обучив нейронную сеть большему количеству итераций. Мы рекомендуем вам попробовать обучить нейронную сеть большему количеству итераций (например, установить maxiter
на 400), а также изменить параметр регуляризации $\lambda$. При правильных настройках обучения можно заставить нейронную сеть идеально соответствовать тренировочному набору.
pred = utils.predict(Theta1, Theta2, X) print('Training Set Accuracy: %f' % (np.mean(pred == y) * 100))
Вывод
Training Set Accuracy: 96.380000
Если вы подписались на меня и написали код выше, поздравляю!
Вы построили нейронную сеть для мультиклассовой классификации с нуля. Это означает, что теперь вы можете использовать TensorFlow с полным пониманием гиперпараметров.
Увидимся в следующем блоге.
«Что хорошего в идее, если она так и останется идеей? Пытаться. Эксперимент. Повторить. Неудача. Попробуйте еще раз. Измени мир».