反向传播
最近研究稀疏张量核心架构,需要用到一些深度学习的知识,比如这里的反向传播。在使用稀疏张量核心进行训练时,一些权重被置为零,从而不进行正向和反向传播。而研究非零权重的反向传播很有意义。为此特意复习了一下本书反向传播这部分。
反向传播的本质就是求偏导数。对于经历了完整大学数学教育的理工科学生,其他理解方法都不如偏导数直观、快捷、高效。因为这是最基本的定义。
本文的神经网络是一个两层的简单神经网络,最后一层是 Logistic Regression(即 Sigmoid 激活函数),执行 二分类任务。
交叉熵损失函数
参考吴恩达深度学习的 PPT:
流程图:
公式总览:
Epoch 和 Batch
Epoch
在深度学习中,Epoch(周期/训练轮次) 是指模型完整遍历一次整个训练数据集的过程,包含以下核心要点:
定义
一个 Epoch 表示所有训练样本均被模型学习一次,包括前向传播、损失计算、反向传播和参数更新。例如,若训练集有 1000 个样本,则完成 1 个 Epoch 即模型处理完这 1000 个样本。
与 Batch 和 Iteration 的关系
- Batch Size:单次输入模型的样本数量(如 100 个样本/批)。
- Iteration(迭代):处理一个 Batch 并更新一次参数的步骤。每个 Epoch 的迭代数由公式计算:
例如,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,并通过可学习的参数恢复网络的表达能力。以下是关键要点:
基本原理
-
归一化步骤:
对每个批次的输入数据 ,计算该批次的均值 和方差 :其中 为批次大小。随后对数据进行标准化:
是为防止除零的小常数(如 )。
-
可学习参数:
引入缩放参数 和平移参数 ,恢复网络的非线性表达能力:这两个参数通过反向传播学习,允许模型自适应调整归一化后的分布。
作用与优势
- 加速训练:减少内部协变量偏移(Internal Covariate Shift),使每层输入分布稳定,允许使用更大的学习率。
- 提高稳定性:缓解梯度消失/爆炸问题,降低对权重初始化的敏感性。
- 正则化效果:通过批次统计量的噪声,间接起到类似Dropout的正则化作用。
应用场景
- 位置:通常置于全连接层或卷积层之后、激活函数(如ReLU)之前。
- 卷积网络:对每个通道独立归一化,统计量基于批次和空间维度()计算。
- 局限性:依赖足够大的批次(如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通过标准化中间层输入,显著提升了深度网络的训练效率和性能,成为现代深度学习中的基础组件之一。