神经网络学习全流程详解:从理论到代码实战

今天我们来全面梳理神经网络的学习过程,从基础概念到完整代码实现,彻底掌握神经网络如何“学习”。

神经网络学习的四大步骤

步骤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. 实验结果分析

从实验结果我们可以观察到:

损失函数下降曲线

  • 随着迭代次数增加,损失函数值逐渐减小
  • 说明神经网络正在有效学习

识别精度曲线

  • 训练数据和测试数据的识别精度同步提升
  • 两条曲线基本重合,说明没有过拟合
  • 模型具有良好的泛化能力

学习要点总结

  1. Mini-batch学习:使用小批量数据而不是全部数据,兼顾效率和效果
  2. 梯度下降:沿着梯度方向更新参数,是神经网络学习的核心
  3. 超参数调整:学习率、批量大小等需要精心设置
  4. 防止过拟合:需要同时监控训练集和测试集的性能
  5. 数值微分vs反向传播:数值微分容易实现但速度慢,反向传播高效但实现复杂

进阶方向

  1. 权重初始化改进:使用Xavier或He初始化,避免梯度消失/爆炸
  2. 优化器升级:从SGD升级为Adam、RMSProp等更先进的优化器
  3. 正则化技术:添加Dropout、L2正则化等防止过拟合
  4. 学习率调度:使用学习率衰减或warmup策略
  5. 批归一化:加速训练并提高模型稳定性

希望这篇详细解析能帮助你真正理解神经网络的学习过程!在实际应用中,记得不仅要关注训练效果,更要关注模型的泛化能力。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐