4.5 学习算法的实现

关于神经网络学习的基础知识,到这里就全部介绍完了。“损失函数”“mini-batch”“梯度”“梯度下降法”等关键词已经陆续登场,这里我们来确认一下神经网络的学习步骤,顺便复习一下这些内容。神经网络的学习步骤如下所示。

前提

神经网络存在合适的权重和偏置,调整权重和偏置以便拟合训练数据的过程称为“学习”。神经网络的学习分成下面 4 个步骤。

步骤 1(mini-batch)

从训练数据中随机选出一部分数据,这部分数据称为 mini-batch。我们的目标是减小 mini-batch 的损失函数的值。

步骤 2(计算梯度)

为了减小 mini-batch 的损失函数的值,需要求出各个权重参数的梯度。梯度表示损失函数的值减小最多的方向。

步骤 3(更新参数)

将权重参数沿梯度方向进行微小更新。

步骤 4(重复)

重复步骤 1、步骤 2、步骤 3。

神经网络的学习按照上面 4 个步骤进行。这个方法通过梯度下降法更新参数,不过因为这里使用的数据是随机选择的mini batch 数据,所以又称为随机梯度下降法(stochastic gradient descent)。“随机”指的是“随机选择的”的意思,因此,随机梯度下降法是“对随机选择的数据进行的梯度下降法”。深度学习的很多框架中,随机梯度下降法一般由一个名为 SGD 的函数来实现。SGD 来源于随机梯度下降法的英文名称的首字母。

下面,我们来实现手写数字识别的神经网络。这里以 2 层神经网络(隐藏层为 1 层的网络)为对象,使用 MNIST 数据集进行学习。

4.5.1 2 层神经网络的类

首先,我们将这个 2 层神经网络实现为一个名为 TwoLayerNet 的类,实现过程如下所示 5。源代码在 ch04/two_layer_net.py 中。

5TwoLayerNet 的实现参考了斯坦福大学 CS231n 课程提供的 Python 源代码。

  1. import sys, os
  2. sys.path.append(os.pardir)
  3. from common.functions import *
  4. from common.gradient import numerical_gradient
  5. class TwoLayerNet:
  6. def __init__(self, input_size, hidden_size, output_size,
  7. weight_init_std=0.01):
  8. # 初始化权重
  9. self.params = {}
  10. self.params['W1'] = weight_init_std * \
  11. np.random.randn(input_size, hidden_size)
  12. self.params['b1'] = np.zeros(hidden_size)
  13. self.params['W2'] = weight_init_std * \
  14. np.random.randn(hidden_size, output_size)
  15. self.params['b2'] = np.zeros(output_size)
  16. def predict(self, x):
  17. W1, W2 = self.params['W1'], self.params['W2']
  18. b1, b2 = self.params['b1'], self.params['b2']
  19. a1 = np.dot(x, W1) + b1
  20. z1 = sigmoid(a1)
  21. a2 = np.dot(z1, W2) + b2
  22. y = softmax(a2)
  23. return y
  24. # x:输入数据, t:监督数据
  25. def loss(self, x, t):
  26. y = self.predict(x)
  27. return cross_entropy_error(y, t)
  28. def accuracy(self, x, t):
  29. y = self.predict(x)
  30. y = np.argmax(y, axis=1)
  31. t = np.argmax(t, axis=1)
  32. accuracy = np.sum(y == t) / float(x.shape[0])
  33. return accuracy
  34. # x:输入数据, t:监督数据
  35. def numerical_gradient(self, x, t):
  36. loss_W = lambda W: self.loss(x, t)
  37. grads = {}
  38. grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
  39. grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
  40. grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
  41. grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
  42. return grads

虽然这个类的实现稍微有点长,但是因为和上一章的神经网络的前向处理的实现有许多共通之处,所以并没有太多新东西。我们先把这个类中用到的变量和方法整理一下。表 4-1 中只罗列了重要的变量,表 4-2 中则罗列了所有的方法。

表 4-1 TwolayerNet类中使用的变量

变量 说明
params 保存神经网络的参数的字典型变量(实例变量)。