# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
# 读入数据
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
iters_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 = max(train_size / batch_size, 1)
for i in range(iters_num):
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)
grad = network.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("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
# 绘制图形
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()
这段代码实现了一个基本的神经网络训练过程,使用了 MNIST 数据集进行手写数字分类。主要功能包括数据加载、网络训练、梯度计算和参数更新。具体功能的解释如下:
1. 导入数据
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
load_mnist
是一个用来加载 MNIST 数据集的函数。MNIST 数据集包含 60000 张训练图片和 10000 张测试图片,每张图片是 28x28 的灰度图像,表示数字 0 到 9。normalize=True
表示对图像进行归一化处理,使得每个像素值在 [0, 1] 范围内。one_hot_label=True
表示标签是 One-Hot 编码格式,即每个标签是一个 10 维的向量,只有对应数字位置为 1,其他为 0。
2. 网络设置
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
TwoLayerNet
是一个两层神经网络类,input_size=784
表示输入层有 784 个神经元(28x28 的图像展开成一个向量),hidden_size=50
表示隐藏层有 50 个神经元,output_size=10
表示输出层有 10 个神经元(对应 10 个数字类别)。
3. 超参数设置
iters_num = 10000 # 适当设定循环的次数
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
iters_num = 10000
:训练的总迭代次数。train_size = x_train.shape[0]
:训练集的样本数。batch_size = 100
:每次使用 100 个样本来进行训练,即每个 mini-batch 包含 100 个数据。learning_rate = 0.1
:学习率,用来控制每次更新权重时的步长。
4. 训练过程
for i in range(iters_num):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 计算梯度
grad = network.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("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
- 迭代训练:通过
for i in range(iters_num)
循环进行训练,每次循环代表一次迭代。 - 批量选择数据:
batch_mask
随机选择 100 个训练样本。 - 计算梯度:调用
network.gradient(x_batch, t_batch)
计算当前批次数据的梯度。 - 更新参数:使用计算出的梯度更新网络的权重和偏置。更新规则是
parameter -= learning_rate * gradient
,即梯度下降法。 - 计算损失:通过
network.loss(x_batch, t_batch)
计算当前批次的损失并保存到train_loss_list
中。 - 计算并打印准确率:每完成一个 epoch(通过
i % iter_per_epoch == 0
检查),计算训练集和测试集的准确率,并打印。
这段代码实现了神经网络的训练过程,并绘制了训练和测试准确率的变化曲线。下面是对代码每个部分的详细解释:
4.1 初始化变量
train_loss_list = [] train_acc_list = [] test_acc_list = []
train_loss_list
用于保存每次训练的损失值(loss),记录训练过程中损失的变化。train_acc_list
用于保存每个 epoch 后的训练准确率。test_acc_list
用于保存每个 epoch 后的测试准确率。iter_per_epoch = max(train_size / batch_size, 1)
- 计算每个 epoch 内需要多少次迭代才能遍历整个训练集。
train_size
是训练数据的样本数量,batch_size
是每次训练时使用的样本数量。iter_per_epoch
表示每个 epoch 内的迭代次数。4.2 训练过程
for i in range(iters_num):
- 循环
iters_num
次,每次循环表示进行一次迭代。iters_num
是总的训练迭代次数。batch_mask = np.random.choice(train_size, batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask]
batch_mask = np.random.choice(train_size, batch_size)
:从训练集x_train
中随机选取batch_size
个样本,batch_mask
是选择的样本索引。x_batch
和t_batch
分别是选中的训练样本和对应的标签。x_batch
是输入数据,t_batch
是标签。# 计算梯度 #grad = network.numerical_gradient(x_batch, t_batch) grad = network.gradient(x_batch, t_batch)
- 计算梯度:
network.gradient(x_batch, t_batch)
计算当前批次数据(x_batch
,t_batch
)的梯度。梯度表示损失函数相对于网络参数(权重和偏置)的变化率,反映了如何更新参数以最小化损失。# 更新参数 for key in ('W1', 'b1', 'W2', 'b2'): network.params[key] -= learning_rate * grad[key]
- 使用梯度下降法更新网络的参数。通过对每个参数(
W1
,b1
,W2
,b2
)应用梯度更新公式:
- 其中,
eta
是学习率(learning_rate
),决定每次更新的步长。loss = network.loss(x_batch, t_batch) train_loss_list.append(loss)
- 计算当前批次的损失(
loss
),并将其添加到train_loss_list
中。4.3 每个 epoch 后的评估
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("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
- 每当一个 epoch(即遍历完整个训练集)结束时,计算训练集和测试集上的准确率。
network.accuracy(x_train, t_train)
:计算训练集上的准确率。network.accuracy(x_test, t_test)
:计算测试集上的准确率。- 将训练准确率和测试准确率分别存储在
train_acc_list
和test_acc_list
中,并打印出每个 epoch 的准确率。总结:
- 代码通过循环进行网络的训练,并在每个 epoch 后计算并输出训练和测试的准确率。
- 使用梯度下降法更新网络的权重和偏置,并通过损失函数(如交叉熵损失)计算每个批次的损失。
5. 绘制准确率图形
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()
- 使用
matplotlib
绘制训练和测试准确率的变化曲线。 train_acc_list
和test_acc_list
保存了每个 epoch 时的训练和测试准确率。- 使用
plt.plot
绘制图形,train acc
用圆圈标记,test acc
用方块标记。 plt.ylim(0, 1.0)
设置 y 轴范围为 0 到 1,表示准确率的范围。plt.legend(loc='lower right')
设置图例的位置。
总结:
这段代码实现了一个基于两层神经网络的手写数字分类任务,通过 MNIST 数据集进行训练和测试。核心过程包括:
- 加载 MNIST 数据集;
- 创建并初始化两层神经网络;
- 使用批量梯度下降法更新网络参数;
- 在每个 epoch 结束时计算并输出训练和测试的准确率;
- 最后绘制训练和测试准确率的变化曲线。