【深度学习笔记】神经网络的学习(3)


神经网络的基础知识,整体就前面那三篇,有了“损失函数”、“mini-batch”、“梯度”、“梯度下降”这些知识,我们就可以实现一个简单的神经网络,然后训练一个人工智障了。

神经网络的学习(训练)过程大致如下:

  1. 从训练数据中随机选出一部分数据,这部分数据称为 mini-batch。我们的目标是减小 mini-batch 的损失函数的值。
  2. 为了减小 mini-batch 的损失函数的值,需要求出各个权重参数的梯度。梯度表示损失函数的值减小最多的方向。
  3. 将权重参数沿梯度方向进行微小更新。
  4. 重复步骤1、2、3。

神经网络权重更新是通过梯度下降来实现的,而我们每次扔进神经网络的数据(mini-batch),是随机选取的,所以这种更新权重的算法被称为随机梯度下降,这也是我们学习到的第一个优化算法———SGD(Stochastic Gradient Descent的首字母),后面还有很多优化算法,几乎都是在SGD基础上做的改进。

下面我们来实现一个两层神经网络,然后使用MNIST数据集训练一个识别手写数字的模型(文末有完整代码下载链接)。

两层神经网络实现

我们先来定义神经网络的结构:

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size,
                 weight_init_std=0.01):
        # 初始化权重
        self.params = {
            # 第一层的参数
            'W1': weight_init_std * np.random.randn(input_size, hidden_size),
            'b1': np.zeros(hidden_size),
            # 第二层的参数
            'W2': weight_init_std * np.random.randn(hidden_size, output_size),
            'b2': np.zeros(output_size)
        }

    # 进行推理(前向传播)
    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)  # 该函数具体实现见文章 【深度学习笔记】神经网络
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)  # 该函数具体实现见文章 【深度学习笔记】神经网络
        return y

    # x:输入数据, t:监督数据,计算损失函数
    def loss(self, x, t):
        y = self.predict(x)
        return cross_entropy_error(y, t)  # 交叉熵误差,具体实现见文章 【深度学习笔记】神经网络的学习(1)

    # 计算精度
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

    # x:输入数据, t:监督数据,计算梯度
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        grads = {}  # 用于保存梯度
        # 数值微分函数,具体实现见文章 【深度学习笔记】神经网络的学习(2)
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        return grads

接下来,我们需要将数据集下载下来,然后进行一些处理,转换成numpy数组,以便稍后训练神经网络。
转换格式这部分不是我们关注的重点,就先省略。
准备好数据,我们接下来就可以训练人工智障了。具体训练代码如下:

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
train_loss_list = []
# 超参数
iters_num = 10000 # 迭代次数
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1 # 学习率
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
for i in range(iters_num):
    # 获取 mini-batch
    print("第{}轮训练...".format(i+1))
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    # 计算梯度
    grad = network.numerical_gradient(x_batch, t_batch)
    # 更新参数
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]
    # 记录学习过程
    loss = network.loss(x_batch, t_batch)
    print("train loss: {}, accuracy: {}".format(loss, network.accuracy(x_test, t_test)))
    train_loss_list.append(loss)
    print("------------------------")

开始训练之后,你会发现迭代的特别慢,这是因为我们的网络中使用数值微分的方法去进行梯度计算再更新参数,根据数值微分的实现,我们不难发现,其计算量很大,这就导致我们训练的很慢。那有没有啥加速的方法呢?答案是肯定的,下篇文章,我们使用“误差反向传播”来加速训练。

代码下载:点击下载

声明:迟於|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 【深度学习笔记】神经网络的学习(3)


栖迟於一丘