神经网络学习全流程详解:从理论到代码实战
Epoch表示所有训练数据都被使用过一次的更新次数。训练数据:60,000个mini-batch大小:100个每个epoch需要:60,000 ÷ 100 = 600次迭代Mini-batch学习:使用小批量数据而不是全部数据,兼顾效率和效果梯度下降:沿着梯度方向更新参数,是神经网络学习的核心超参数调整:学习率、批量大小等需要精心设置防止过拟合:需要同时监控训练集和测试集的性能数值微分vs反向传播
·
神经网络学习全流程详解:从理论到代码实战
今天我们来全面梳理神经网络的学习过程,从基础概念到完整代码实现,彻底掌握神经网络如何“学习”。
神经网络学习的四大步骤
步骤1:mini-batch(小批量数据)
从训练数据中随机选取一部分数据,称为mini-batch。我们的目标是减小这个小批量数据的损失函数值。
步骤2:计算梯度
为了减小损失函数值,需要计算每个权重参数的梯度。梯度指向损失函数下降最快的方向。
步骤3:更新参数
沿梯度方向微小调整权重参数。
步骤4:重复迭代
不断重复上述三个步骤,直到模型收敛。
这种基于随机选取的小批量数据的梯度下降法,被称为随机梯度下降法(SGD)。
实战:双层神经网络实现
下面我们实现一个双层神经网络(1个隐藏层),使用MNIST手写数字数据集进行训练。
import sys, os
sys.path.append(os.pardir)
from common.functions import *
from common.gradient import numerical_gradient
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)
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
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 = {}
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
关键变量说明
| 变量名 | 说明 |
|---|---|
params |
保存权重参数的字典 |
params['W1'] |
第1层权重参数 |
params['b1'] |
第1层偏置参数 |
params['W2'] |
第2层权重参数 |
params['b2'] |
第2层偏置参数 |
grads |
保存梯度的字典 |
方法说明
| 方法名 | 功能 |
|---|---|
__init__ |
初始化权重参数 |
predict |
前向传播推理 |
loss |
计算损失函数值 |
accuracy |
计算识别精度 |
numerical_gradient |
计算梯度(数值微分版) |
gradient |
计算梯度(反向传播版) |
Mini-batch学习实现
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
# 加载MNIST数据集
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
train_loss_list = []
train_acc_list = []
test_acc_list = []
# 超参数设置
iters_num = 10000 # 迭代次数
batch_size = 100 # mini-batch大小
learning_rate = 0.1 # 学习率
train_size = x_train.shape[0]
iter_per_epoch = max(train_size / batch_size, 1)
# 创建神经网络实例
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
for i in range(iters_num):
# 步骤1: 获取mini-batch
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 步骤2: 计算梯度
grad = network.numerical_gradient(x_batch, t_batch)
# grad = network.gradient(x_batch, t_batch) # 反向传播版(更快)
# 步骤3: 更新参数
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)
# 每个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(f"train acc: {train_acc:.4f}, test acc: {test_acc:.4f}")
关键概念解析
1. 什么是Epoch?
Epoch表示所有训练数据都被使用过一次的更新次数。例如:
- 训练数据:60,000个
- mini-batch大小:100个
- 每个epoch需要:60,000 ÷ 100 = 600次迭代
2. 为什么要监控测试数据?
只关注训练数据的损失函数下降是不够的,我们还需要确认模型是否具有泛化能力。
过拟合是常见问题:
- 训练数据识别精度高
- 但测试数据识别精度低
- 说明模型只是"记住了"训练数据
3. 实验结果分析
从实验结果我们可以观察到:
损失函数下降曲线:
- 随着迭代次数增加,损失函数值逐渐减小
- 说明神经网络正在有效学习
识别精度曲线:
- 训练数据和测试数据的识别精度同步提升
- 两条曲线基本重合,说明没有过拟合
- 模型具有良好的泛化能力
学习要点总结
- Mini-batch学习:使用小批量数据而不是全部数据,兼顾效率和效果
- 梯度下降:沿着梯度方向更新参数,是神经网络学习的核心
- 超参数调整:学习率、批量大小等需要精心设置
- 防止过拟合:需要同时监控训练集和测试集的性能
- 数值微分vs反向传播:数值微分容易实现但速度慢,反向传播高效但实现复杂
进阶方向
- 权重初始化改进:使用Xavier或He初始化,避免梯度消失/爆炸
- 优化器升级:从SGD升级为Adam、RMSProp等更先进的优化器
- 正则化技术:添加Dropout、L2正则化等防止过拟合
- 学习率调度:使用学习率衰减或warmup策略
- 批归一化:加速训练并提高模型稳定性
希望这篇详细解析能帮助你真正理解神经网络的学习过程!在实际应用中,记得不仅要关注训练效果,更要关注模型的泛化能力。
更多推荐
所有评论(0)