AICS 第二章 深度学习基础


反向传播

最近研究稀疏张量核心架构,需要用到一些深度学习的知识,比如这里的反向传播。在使用稀疏张量核心进行训练时,一些权重被置为零,从而不进行正向和反向传播。而研究非零权重的反向传播很有意义。为此特意复习了一下本书反向传播这部分。

反向传播的本质就是求偏导数。对于经历了完整大学数学教育的理工科学生,其他理解方法都不如偏导数直观、快捷、高效。因为这是最基本的定义。

Input da[l]\text{Input} \ da^{[l]}

本文的神经网络是一个两层的简单神经网络,最后一层是 Logistic Regression(即 Sigmoid 激活函数),执行 二分类任务

交叉熵损失函数

L=1Mi=1N[yilog(y^i)+(1yi)log(1y^i)]L = - \frac{1}{M}\sum^{N}_{i = 1}[y_i\log(\hat y_i) + (1 - y_i)\log(1 - \hat y_i)]

参考吴恩达深度学习的 PPT:

流程图:

神经网络的反向传播计算示意图

公式总览:

公式总览

Epoch 和 Batch

Epoch

在深度学习中,Epoch(周期/训练轮次) 是指模型完整遍历一次整个训练数据集的过程,包含以下核心要点:

定义

一个 Epoch 表示所有训练样本均被模型学习一次,包括前向传播、损失计算、反向传播和参数更新。例如,若训练集有 1000 个样本,则完成 1 个 Epoch 即模型处理完这 1000 个样本。

与 Batch 和 Iteration 的关系

  • Batch Size:单次输入模型的样本数量(如 100 个样本/批)。
  • Iteration(迭代):处理一个 Batch 并更新一次参数的步骤。每个 Epoch 的迭代数由公式计算:

    Iterations per Epoch=训练集样本总数Batch Size\text{Iterations per Epoch} = \frac{\text{训练集样本总数}}{\text{Batch Size}}

    例如,1000 个样本、Batch Size=100时,1 个 Epoch 需 10 次迭代。

作用

  • 通过多个 Epoch 逐步优化模型参数,使损失函数最小化。
  • 单次 Epoch 通常不足以充分学习数据特征,需重复多次(如 10-100个 Epoch)以提高模型性能。

注意事项

  • 过拟合风险:Epoch 过多可能导致模型记忆训练数据噪声,泛化能力下降。
  • 早停策略:监控验证集性能,在模型不再改进时提前终止训练。

总结:Epoch 是训练进度的基础单位,需结合 Batch Size 和迭代次数共同调节,以平衡训练效率与模型性能。

Batch

在深度学习中,Batch(批次) 是指一次性输入模型进行训练的一组样本,其核心概念和要点如下:

定义与作用

  • Batch:训练过程中同时处理的一组样本,用于单次参数更新。
  • 目的:通过批量处理数据,提高计算效率(利用GPU并行能力)并稳定梯度估计。

Batch Size

一个 Batch 中的样本数量(如32、64、128等)定义为 Batch Size。其影响的因素包括:

  • 训练速度:较大的 Batch Size 减少迭代次数,但需更多内存。
  • 梯度稳定性:较大的 Batch Size 降低梯度方差,但可能陷入局部最优;较小的 Batch Size 引入噪声,可能提升泛化能力。

计算机制

  • 并行处理:模型通过张量运算同时处理整个 Batch,无需为每个样本复制参数。
  • 梯度更新:Batch 内样本的梯度被平均或累加后统一更新模型参数。

选择策略

  • 硬件限制:根据 GPU 内存选择最大可行 Batch Size。
  • 实验调整:常见初始值为 32 或 64,再根据训练效果动态调整。
  • 学习率配合:较大的 Batch Size 通常需更大的学习率。

小结

Batch是深度学习训练中的基本数据单元,其大小(Batch Size)需平衡效率、内存和模型性能。合理选择Batch Size是优化训练过程的关键步骤之一。

示例代码(PyTorch)

此时示例来自 ResNet/VGG 网络的训练代码:

import torch
import numpy as np
from tqdm import tqdm
import torch.nn as nn
import torch.optim as optim
from utils.readData import read_dataset
from models.resnet import ResNet18

# 设置模型
model_name = 'resnet18'
# model_name = 'VGG16'

# 设置计算
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 读数据
batch_size = 128
train_loader, valid_loader, test_loader = read_dataset(batch_size=batch_size, pic_path='data')

# 加载模型(使用预处理模型,修改最后一层,固定之前的权重)
n_class = 10

if model_name == 'VGG16':
    model = VGG(model_name)
else:
    model = ResNet18()

model = model.to(device)
# 使用交叉熵损失函数
criterion = nn.CrossEntropyLoss().to(device)

# 开始训练
# 设置训练的轮数(epoch 数)
n_epochs = 250
valid_loss_min = np.inf  # track change in validation loss
accuracy = []
lr = 0.01
counter = 0
for epoch in tqdm(range(1, n_epochs + 1)):

    # keep track of training and validation loss
    train_loss = 0.0
    valid_loss = 0.0
    total_sample = 0
    right_sample = 0

    # 动态调整学习率
    if counter / 10 == 1:
        counter = 0
        lr = lr * 0.5
    optimizer = optim.SGD(model.parameters(), lr=lr, momentum=0.9, weight_decay=5e-4)
    ###################
    # 训练集的模型 #
    ###################
    model.train()  # 作用是启用batch normalization和drop out
    for data, target in train_loader:
        data = data.to(device)
        target = target.to(device)
        # clear the gradients of all optimized variables(清除梯度)
        optimizer.zero_grad()
        # forward pass: compute predicted outputs by passing inputs to the model
        # (正向传递:通过向模型传递输入来计算预测输出)
        output = model(data).to(device)  # (等价于output = model.forward(data).to(device) )
        # calculate the batch loss(计算损失值)
        loss = criterion(output, target)
        # backward pass: compute gradient of the loss with respect to model parameters
        # (反向传递:计算损失相对于模型参数的梯度)
        loss.backward()
        # perform a single optimization step (parameter update)
        # 执行单个优化步骤(参数更新)
        optimizer.step()
        # update training loss(更新损失)
        train_loss += loss.item() * data.size(0)

    ######################
    # 验证集的模型#
    ######################

    model.eval()  # 验证模型
    for data, target in valid_loader:
        data = data.to(device)
        target = target.to(device)
        # forward pass: compute predicted outputs by passing inputs to the model
        output = model(data).to(device)
        # calculate the batch loss
        loss = criterion(output, target)
        # update average validation loss
        valid_loss += loss.item() * data.size(0)
        # convert output probabilities to predicted class(将输出概率转换为预测类)
        _, pred = torch.max(output, 1)
        # compare predictions to true label(将预测与真实标签进行比较)
        correct_tensor = pred.eq(target.data.view_as(pred))
        # correct = np.squeeze(correct_tensor.to(device).numpy())
        total_sample += batch_size
        for i in correct_tensor:
            if i:
                right_sample += 1
    print("Accuracy:", 100 * right_sample / total_sample, "%")
    accuracy.append(right_sample / total_sample)

    # 计算平均损失
    train_loss = train_loss / len(train_loader.sampler)
    valid_loss = valid_loss / len(valid_loader.sampler)

    # 显示训练集与验证集的损失函数
    print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(
        epoch, train_loss, valid_loss))

    # 如果验证集损失函数减少,就保存模型。
    if valid_loss <= valid_loss_min:
        print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(valid_loss_min, valid_loss))
        torch.save(model.state_dict(), f'checkpoint/{model_name}_cifar10.pt')
        valid_loss_min = valid_loss
        counter = 0
    else:
        counter += 1

此代码中,外层循环控制Epoch数量,内层循环处理每个Batch。

Batch Normalization

Batch Normalization(批量归一化,简称BN) 是一种用于深度神经网络的技术,旨在通过标准化每一层的输入分布来加速训练并提高模型稳定性。其核心思想是对每个批次的输入数据进行归一化,使其均值为0、方差为1,并通过可学习的参数恢复网络的表达能力。以下是关键要点:

基本原理

  • 归一化步骤
    对每个批次的输入数据 xix_i,计算该批次的均值 μB\mu_B 和方差 σB2\sigma_B^2

    μB=1mi=1mxi,σB2=1mi=1m(xiμB)2\mu_B = \frac{1}{m}\sum_{i=1}^m x_i, \quad \sigma_B^2 = \frac{1}{m}\sum_{i=1}^m (x_i - \mu_B)^2

    其中 mm 为批次大小。随后对数据进行标准化:

    x^i=xiμBσB2+ϵ\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}

    ϵ\epsilon 是为防止除零的小常数(如 10510^{-5})。

  • 可学习参数
    引入缩放参数 γ\gamma 和平移参数 β\beta,恢复网络的非线性表达能力:

    yi=γx^i+βy_i = \gamma \hat{x}_i + \beta

    这两个参数通过反向传播学习,允许模型自适应调整归一化后的分布。

作用与优势

  • 加速训练:减少内部协变量偏移(Internal Covariate Shift),使每层输入分布稳定,允许使用更大的学习率。
  • 提高稳定性:缓解梯度消失/爆炸问题,降低对权重初始化的敏感性。
  • 正则化效果:通过批次统计量的噪声,间接起到类似Dropout的正则化作用。

应用场景

  • 位置:通常置于全连接层或卷积层之后、激活函数(如ReLU)之前。
  • 卷积网络:对每个通道独立归一化,统计量基于批次和空间维度(N×H×WN \times H \times W)计算。
  • 局限性:依赖足够大的批次(如batch size ≥ 16),小批次或序列模型(如RNN)中效果较差,此时可改用Layer Normalization。

实现示例(PyTorch)

import torch.nn as nn
bn = nn.BatchNorm2d(num_features=64)  # 对64通道的卷积输出归一化

在训练时,BN层会动态计算批次统计量;推理时则使用训练期间累积的全局均值和方差。

与其他归一化的对比

  • Layer Normalization (LN):对单个样本的所有特征归一化,适用于RNN/Transformer。
  • Instance Normalization (IN):风格迁移任务中常用,对每个样本的每个通道独立归一化。

总结:BN通过标准化中间层输入,显著提升了深度网络的训练效率和性能,成为现代深度学习中的基础组件之一。


Author: Yixiang Zhang
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Yixiang Zhang !
评论
  TOC