top of page
アンカー 1

一、前文回顾

神经网络的基本知识已经全部介绍完了。主要包括了以下几个:

①激活函数

②softmax函数

③损失函数

④批处理

⑤梯度

⑥梯度下降法

今天就把这些都归纳起来,然后完整的实现神经网络的自主学习过程。

二、神经网络的自主学习流程

以前也有提到过,神经网络所谓的自主学习,其实就是一个寻找最佳权重参数值的过程。或者说寻找损失函数最小值的过程。归纳起来的话主要是以下几个步骤。

①随机选取样品从大量的训练数据中随机选择一部分进行训练。

②求梯度为了获取损失函数的最小值,求出权重参数的梯度。

③更新权重参数沿着梯度方向对权重参数进行一次细微的调整。

④重复上面①②③

三、实现神经网络

1.先定义一个神经网络类。

# 定义神经网络类
class DeepVisionZeroNet:

    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # 权重初期化
        # 初始化参数W1(形状为input_size行,hidden_size列,大小在0-1之间并且符合高斯分布的数组)
        # 初始化参数W2(形状为hidden_size行,output_size列,大小在0-1之间并且符合高斯分布的数组)
        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  # W1*x+b1
        z1 = sigmoid(a1)  # 1 / (1 + np.exp(-a1)) 激活函数
        a2 = np.dot(z1, W2) + b2  # z1*W2+b2
        y = softmax(a2)  # softmax函数

        return y

    # 求损失函数值
    # x:样本数据
    # t:标签(正确答案)
    def loss(self, x, t):
        # 先推理
        y = self.predict(x)
        # 求出推理值和正确值之间的差距:损失函数值
        return cross_entropy_error(y, t)

    # 计算神经网络的识别准确率
    # 样本识别正确数/样本总数
    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

    # 求梯度
    def numerical_gradient(self, x, t):
        # 设定损失函数
        loss_W = lambda W: self.loss(x, t)
        # 求出每一个参数的梯度
        grads = {'W1': numerical_gradient(loss_W, self.params['W1']),
                 'b1': numerical_gradient(loss_W, self.params['b1']),
                 'W2': numerical_gradient(loss_W, self.params['W2']),
                 'b2': numerical_gradient(loss_W, self.params['b2'])}

        return grads

    # 保存权重参数
    def save_params(self, file_name="params_two_layer.pkl"):
        params = {}
        for key, val in self.params.items():
            params[key] = val
        with open(file_name, 'wb') as f:
            pickle.dump(params, f)

2.实现神经网络学习过程。

if __name__ == "__main__":
    # 读取MNIST手写数字集(详细参考第七弹)
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
    print("x_train:", x_train.shape)
    print("t_train:", t_train.shape)
    print("x_test:", x_test.shape)
    print("t_test:", t_test.shape)
    # 实例化神经网络
    network = DeepVisionZeroNet(input_size=784, hidden_size=50, output_size=10)

    step_num = 10000  # 设定梯度下降法的步数
    train_size = x_train.shape[0]
    batch_size = 100  # 批处理数
    learning_rate = 0.1  # 设定梯度下降法的步长(学习率)
    # 记录损失函数值
    train_loss_list = []
    # 记录训练精度
    train_acc_list = []
    # 记录测试精度
    test_acc_list = []
    # 每iter_per_epoch次保存一次训练精度和测试精度
    iter_per_epoch = max(train_size / batch_size, 1)

    for i in range(step_num):
        # 随机选取batch_size个样品
        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)
        train_loss_list.append(loss)

        if i % iter_per_epoch == 0:
            train_acc = network.accuracy(x_train, t_train)
            test_acc = network.accuracy(x_test, t_test)
            train_acc_list.append(train_acc)
            test_acc_list.append(test_acc)
            print(i, " train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
        print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "Number of steps completed:", i)
    # 保存最终的权重参数
    network.save_params()
    # 把训练精度和损失精度用图标表示出来
    markers = {'train': 'o', 'test': 's'}
    x = np.arange(len(train_acc_list))
    plt.plot(x, train_acc_list, label='train acc')
    plt.plot(x, test_acc_list, label='test acc', linestyle='--')
    plt.xlabel("epochs")
    plt.ylabel("accuracy")
    plt.ylim(0, 1.0)
    plt.legend(loc='lower right')
    plt.show()

四、总结

虽然我们实现了神经网络的学习过程,但是很遗憾,我自己的电脑运行起来的话,每一步大概需要45秒,10000步(step_num)的话大概需要125小时,这是一个很漫长的过程。一个最简单的神经网络却需要花费这么多时间,那要是几十层的神经网络岂不是得几十年了,显然这很不现实。下节就要来说说为什么这么慢,以及怎么解决。

bottom of page