神经网络的训练
训练流程
- 准备数据集
- 随机划分mini-batch
- 计算损失函数L对参数W,b的梯度
- 更新参数,将权重参数沿梯度方向进行微小更新
- 重复上述过程,记录每个平均损失函数,训练集准确率,测试集准确率的值
代码结构
- data文件夹存储数据集
- functions.py 存储了sigmoig,softmax等众多基础函数
- layers.py 包含了神经网络各环节正向传播与反向传播的调用函数,为实现反向传播法计算梯度提供基础
- two_layer_net.py 存储了设计了两层神经网络的结构,存储了预测与训练所需要的直接调用的代码
- train_neuralnet.py 是调用上述代码进行预测与数据记录、可视化的主进程
核心代码详解
two_layer_net.py
# coding: utf-8
import os
import struct
import numpy as np
from layers import *
from collections import OrderedDict
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01):
# 初始化权重
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
# 生成层
self.layers = OrderedDict()
self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
self.layers['Relu1'] = Relu()
self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])
self.lastLayer = SoftmaxWithLoss()
def load_mnist(self, path=".\\data", kind='train'): # kind是train或test
labels_path = os.path.join(path, '%s-labels.idx1-ubyte' % kind) # 标签文件路径
images_path = os.path.join(path, '%s-images.idx3-ubyte' % kind) # 图像文件路径
with open(labels_path, 'rb') as lbpath:
magic, n = struct.unpack('>II', lbpath.read(8)) # 读取文件头
labels = np.fromfile(lbpath, dtype=np.uint8) # 读取标签
with open(images_path, 'rb') as imgpath:
magic, num, rows, cols = struct.unpack('>IIII', imgpath.read(16)) # 读取文件头
images = np.fromfile(imgpath, dtype=np.uint8).reshape(len(labels), 784) # 读取图像并转换为784维向量
return images, labels
def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)
return x
# x:输入数据, t:监督数据
def loss(self, x, t):
y = self.predict(x)
return self.lastLayer.forward(y, t)
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
if t.ndim != 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 = {}
grads['W1'] = self.gradient(loss_W, self.params['W1'])
grads['b1'] = self.gradient(loss_W, self.params['b1'])
grads['W2'] = self.gradient(loss_W, self.params['W2'])
grads['b2'] = self.gradient(loss_W, self.params['b2'])
return grads
def gradient(self, x, t):
# forward
self.loss(x, t)
# backward
dout = 1
dout = self.lastLayer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
# 设定
grads = {}
grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db
return grads
这段代码用于创建一个具有两个隐藏层的神经网络。这个类包含了初始化网络、加载MNIST数据集、前向传播、计算损失、计算准确率、计算数值梯度等方法。
-
__init__
方法:初始化网络,包括设置权重和偏置,创建层,并设置最后一层为SoftmaxWithLoss
。 -
load_mnist
方法:加载MNIST数据集,包括训练集和测试集。数据集的标签和图像分别存储在.idx1-ubyte
和.idx3-ubyte
文件中。 -
predict
方法:进行前向传播,计算输出。在predict
方法中,使用了OrderedDict
来存储网络层,这样可以保证前向传播和反向传播的顺序。 -
loss
方法:计算损失,使用SoftmaxWithLoss
层。 -
accuracy
方法:计算准确率。 -
numerical_gradient
方法:计算数值梯度,用于调试。 -
gradient
方法:计算梯度,用于反向传播。
train_neuralnet.py
这段代码实现了一个简单的两层神经网络(TwoLayerNet),并使用MNIST数据集进行训练和测试。以下是代码的详细解释:
-
导入必要的库:
import numpy as np from two_layer_net import TwoLayerNet import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation
-
初始化网络:
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
这里初始化了一个两层神经网络,输入层大小为784(对应28x28的MNIST图像),隐藏层大小为50,输出层大小为10(对应10个类别)。
-
加载MNIST数据集:
x_train, t_train = network.load_mnist(kind="train") x_test, t_test = network.load_mnist(kind="t10k")
使用
TwoLayerNet
类中的load_mnist
方法加载训练集和测试集。 -
设置训练参数:
iters_num = 10000 train_size = x_train.shape[0] batch_size = 100 learning_rate = 1e-3 iter_per_epoch = train_size / batch_size
-
初始化记录训练和测试准确率的列表:
train_loss_list = [] train_acc_list = [] test_acc_list = []
-
开始训练循环:
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={}".format(train_acc), "test_acc={}".format(test_acc))
- 每次迭代中,随机选择一个批次的数据进行训练。
- 计算梯度并更新网络参数。
- 记录损失值。
- 每经过一个epoch(即遍历一次整个训练集),计算并记录训练集和测试集的准确率。
-
绘制训练和测试准确率的变化图:
fig, ax = plt.subplots() line1, = ax.plot(range(len(train_acc_list)), train_acc_list, label='Train Accuracy', linestyle='-') line2, = ax.plot(range(len(test_acc_list)), test_acc_list, label='Test Accuracy', linestyle='--') ax.set_xlabel('Epoch') ax.set_ylabel('Accuracy') ax.set_title('Training and Testing Accuracy') ax.legend() plt.grid() plt.show()
-
保存网络参数:
np.savetxt(".\\data\\W1.txt", network.params["W1"]) np.savetxt(".\\data\\b1.txt", network.params["b1"]) np.savetxt(".\\data\\W2.txt", network.params["W2"]) np.savetxt(".\\data\\b2.txt", network.params["b2"])
将训练好的网络参数保存到文件中。
总结来说,这段代码实现了一个简单的两层神经网络,并使用MNIST数据集进行训练和测试,同时记录并绘制了训练和测试准确率的变化。
数据集与完整代码请关注公众号"逃离小星球"发送关键字“code101”获取!
感谢支持!