深度学习简介
1.1 什么是深度学习
- 定义:深度学习(Deep Learning)是机器学习的分支,是一种以人工神经网络为架构、对数据进行特征学习的算法。其中的”深度”指网络中使用多层结构。
- 核心思想:通过模仿人脑的神经网络来处理和分析复杂的数据,从大量数据中自动提取复杂特征,擅长处理高维数据(图像、语音、文本)。
- 与机器学习/人工智能的关系:机器学习是实现人工智能的一种途径;深度学习是机器学习的一个子集,是实现机器学习的一种方法。
1.2 与传统机器学习的区别
| 对比项 | 传统机器学习 | 深度学习 |
|---|---|---|
| 特征提取 | 依赖人工设计特征并进行特征提取 | 不需要人工,依赖算法自动提取特征 |
| 网络结构 | 一般无多层神经网络结构 | 多层人工神经网络,逐层非线性变换 |
| 数据要求 | 相对较小 | 需要大量标注数据 + 强大计算资源(GPU) |
| 可解释性 | 较好 | 差,被称为”黑箱” |
1.3 深度学习四大特点
- 多层非线性变换:模型由多个层次组成,每层应用非线性激活函数对输入变换。低层捕捉简单特征(边缘、颜色),高层识别复杂模式(物体、面部)。
- 自动特征提取:无需人工特征工程,自动从原始数据学习特征。
- 大数据和计算能力:需要大量标注数据和 GPU 等计算资源。
- 可解释性差:内部机制不透明,被称为”黑箱”。
1.4 常见的深度学习模型
- CNN(卷积神经网络):主要用于图像处理(图像分类、目标检测、图像分割);用卷积层自动提取局部特征,池化层减少参数提高效率。
- RNN(循环神经网络):处理序列数据(NLP、语音识别);有记忆功能、可处理时间依赖性,但标准 RNN 难以捕捉长期依赖。
- 自编码器(Autoencoders):无监督学习模型,用于降维、特征学习、异常检测;由编码器(压缩为低维表示)和解码器(从低维重建原始输入)组成。
- GAN(生成对抗网络):由生成器和判别器两个子网络组成;生成器创建逼真假样本,判别器区分真假;用于图像生成、视频合成。
- Transformer:主要用于 NLP(机器翻译、文本生成);摒弃递归结构,采用自注意力机制(self-attention),可并行处理整个句子。
- 其他(PPT 补充):深度强化学习(DRL)、图神经网络(GNN)。
1.5 应用场景
- 计算机视觉:图像分类(人脸识别、医疗影像病变检测)、目标检测(自动驾驶行人检测、监控入侵检测)、面部识别(手机解锁)、图像生成(风格迁移、老照片修复)。
- 自然语言处理:机器翻译(Google 翻译)、情感分析(社交媒体监控)、文本生成(写作助手)、语音识别(Siri/Alexa)、聊天机器人(客服机器人、GPT 类虚拟助手)。
- 推荐系统:电影/音乐推荐(Netflix、Spotify)、电商推荐(亚马逊、淘宝)、社交媒体推荐(Facebook、Instagram)。
- 其他:自动驾驶、医疗健康、工业与制造业、语音与音频处理。
1.6 发展历史与里程碑
人工智能三次浪潮(PPT):
- 第一次浪潮(1950s–1970s 符号主义):1950 图灵设计国际象棋程序;1962 IBM Arthur Samuel 跳棋程序战胜人类高手。
- 第二次浪潮(1980s–2000 统计主义):1993 Vapnik 提出 SVM;1997 IBM 深蓝战胜卡斯帕罗夫。
- 第三次浪潮(2012–2016 神经网络):2012 AlexNet;2016 Google AlphaGo 战胜李世石(深度学习/深度强化学习进入公众视野)。
- 大规模预训练模型(2017 至今):2017 Transformer;2018 BERT 和 GPT;2022 ChatGPT 进入大模型 AIGC 阶段。
深度学习自身发展史:
- 早期探索(1940s–1980s):20 世纪 40 年代皮茨(Walter Pitts)和麦卡洛克(Warren McCulloch)提出 McCulloch-Pitts 神经元;1958 罗森布拉特(Frank Rosenblatt)提出感知器(简单二分类);1960 年代末出现多层感知器(MLP),受限于计算能力和数据量。
- 挑战与瓶颈(1980s–1990s):1986 年反向传播(Backpropagation)算法提出(Hinton、Rumelhart 等人),使多层网络可通过梯度下降优化参数解决非线性问题;但因计算资源限制,SVM、决策树成为主流。
- 复兴与突破(2000s–2010s):
- 2006 年 Hinton 团队提出深度信念网络(DBN),引入无监督预训练,标志深度学习复兴。
- 2012 年 AlexNet(Alex Krizhevsky)在 ImageNet 图像分类竞赛显著提升精度(比传统方法提高 20% 以上),深度学习开山之作。
- 2014 年 GANs(Ian Goodfellow 等人)提出,开启生成模型新时代。
- 2015 年 ResNet(何凯明)提出,通过残差连接解决深层网络的梯度消失/爆炸,可训练 50/152 层极深网络。
- 爆发期(2016 至今):2016 AlphaGo;2017 Transformer;2018 BERT/GPT;2022 ChatGPT。
1.7 容易考的点
- 深度学习与传统机器学习的本质区别 → 自动特征提取 vs 人工特征工程。
- “深度”的含义 → 网络中使用多层(隐藏层数量决定深度)。
- 深度学习被称为”黑箱”的原因 → 可解释性差。
- 各里程碑人物/年份对应关系:1986 BP 算法、2006 DBN、2012 AlexNet、2014 GAN、2015 ResNet、2017 Transformer、2022 ChatGPT。
- AlexNet 的意义 → 深度学习在计算机视觉领域的开山之作;ResNet 的意义 → 解决梯度消失/爆炸,允许训练极深网络。
二、PyTorch 框架
2.1 PyTorch 简介与特点
- 定义:PyTorch 是基于 Python 语言的深度学习框架,将数据封装成张量(Tensor)处理;提供构建、训练、部署 ML/DL 模型的工具;广泛应用于 CV、NLP、强化学习。
- 安装:
pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple - 六大特点:
- 类似 NumPy 的张量计算:基本数据结构为 Tensor,具有 GPU 加速(CUDA) 能力。
- 自动微分系统(autograd):自动计算每个参数的梯度,支持动态计算图。
- 深度学习库 torch.nn:预构建层(全连接、卷积、RNN 等)、损失函数(交叉熵、MSE)、优化算法(SGD、Adam);
nn.Module是构建神经网络的基础类。 - 动态计算图:运行时构建和修改模型结构,灵活、易调试。
- GPU 加速:
tensor.to(device)轻松在 CPU/GPU 间转移数据和模型。 - 跨平台支持:CPU/GPU/TPU、Linux/Windows/macOS、多 GPU/分布式训练。
- 与 TensorFlow 对比:PyTorch 基于动态图,TensorFlow 1.x 基于静态计算图(TF 2.x 支持动态图);PyTorch 更灵活易调试,API 更贴近 Python,在学术界更流行。
- 发展历史:Torch(Ronan Collobert 等人)→ Torch7(Lua)→ 2016 PyTorch 0.1.0(FAIR,Facebook 人工智能研究院)→ 0.2.0 引入动态图(制胜 TensorFlow 的关键)→ 2018 1.0(首个稳定版,Eager 模式)→ 2.0(
torch.compile加速、TorchDynamo 替换 torch.jit.trace/script)。 - 课堂笔记补充:pytorch 已更新到 2.5 版本;可在 GPU/TPU/NPU 上运行。
2.2 张量(Tensor)基础
2.2.1 什么是张量
- 张量 = 元素为同一种数据类型的多维矩阵(与 NumPy 数组类似),以”类”的形式封装运算方法。
- 0 维=标量;1 维=向量/矢量;2 维=矩阵;多个二维张量组成三维张量,依此类推。
- 默认数据类型:float32(torch.FloatTensor)。
2.2.2 张量创建(核心 API)
| API | 作用 | 要点 |
|---|---|---|
torch.tensor(data=, dtype=) | 按指定数据创建 | numpy(float64) 传入则张量为 float64;列表默认 float32 |
torch.Tensor(size=) | 按形状创建(也可按数据) | 只给形状时内存未初始化(垃圾值) |
torch.IntTensor/FloatTensor/DoubleTensor/ShortTensor/LongTensor() | 创建指定类型张量 | 元素类型不正确会自动类型转换(如 2.5→2 截断) |
torch.arange(start=, end=, step=) | 固定步长线性张量 | 左闭右开 [start, end) |
torch.linspace(start=, end=, steps=) | 固定元素数线性张量 | 左闭右闭;step=(end-start)/(steps-1) |
torch.rand/randn(size=) | 随机浮点张量 | randn 为标准正态 |
torch.randint(low=, high=, size=) | 随机整数张量 | 左闭右开 |
torch.initial_seed() / torch.manual_seed(seed=) | 查看/设置随机种子 | 保证实验可复现 |
torch.zeros/ones/full(size=, fill_value=) 及 *_like(input=) | 全 0/全 1/全指定值张量 | like 版本按给定张量形状创建 |
tensor.type(dtype=)、tensor.half/float/double/short/int/long() | 元素类型转换 | 如 .double() 转 float64 |
2.2.3 张量类型转换
- 张量 → NumPy:
tensor.numpy(),共享内存(改一个另一个跟着变),用.numpy().copy()避免共享。 - NumPy → 张量:
torch.from_numpy(ndarray)共享内存;torch.tensor(ndarray)不共享内存。 - 提取数值:单元素张量用
.item()。
2.2.4 数值计算
- 基本运算:
+ - * / -;函数形式add/sub/mul/div/neg(不修改原数据);带下划线版本add_()/sub_()/mul_()/div_()/neg_()直接修改原数据。 - 点乘(Hadamard 积):相同形状张量对应位置元素相乘,
mul或*。 - 矩阵乘法:要求 (n,m)×(m,p)→(n,p);运算符
@或torch.matmul(input, other)(形状不同的张量只要最后几个维度符合矩阵乘法规则即可)。 - 运算函数:
mean(dim=)/sum(dim=)/min/max(dim=)/pow(exponent=)/sqrt()/exp()/log()/log2()/log10();dim=0 按列、dim=1 按行;mean 要求张量为 Float/Double 类型。
2.2.5 索引操作
- 简单行列索引:
data[0](第 0 行)、data[:, 0](第 0 列)。 - 列表索引:
data[[0,1],[1,2]]取 (0,1)、(1,2) 两个位置;data[[[0],[1]],[1,2]]取 0、1 行的 1、2 列共 4 个元素。 - 范围索引(切片):
data[:3, :2]、data[2:, :2]。 - 布尔索引:
data[data[:, 2] > 5](第 3 列大于 5 的行)、data[:, data[1] > 5]。 - 多维索引:
data[0,:,:]、data[:,0,:]、data[:,:,0]。
2.2.6 形状操作
| 函数 | 作用 | 要点 |
|---|---|---|
reshape(shape=) | 改变维度,数据不变 | 可用 -1 自动计算某维度;连续/非连续均可 |
squeeze(dim=) | 删除形状为 1 的维度(降维) | 不指定 dim 删除所有为 1 的维度;指定 dim 且该维不为 1 则不生效 |
unsqueeze(dim=) | 在指定位置加形状为 1 的维度(升维) | dim=-1 表示最后一维 |
transpose(dim0, dim1) | 交换两个指定维度 | 如 (2,3,4) 交换 3、4 → (2,4,3) |
permute(dims=) | 一次交换更多维度 | 如 permute([1,2,0]) |
view(shape=) | 修改形状 | 只能用于内存连续的张量;经 transpose/permute 后不连续,需先 .contiguous() |
is_contiguous() | 判断张量是否内存连续 | 返回 True/False |
2.2.7 拼接操作
torch.cat([t1,t2], dim=):沿现有维度拼接,不改变维度数,除拼接维外其他维度必须匹配(拼接维数值相加)。torch.stack([t1,t2], dim=):在新维度上堆叠,增加一个新维度,所有输入形状必须完全相同。
2.3 自动微分模块(autograd)
- 概念:”梯度”= 对函数求导得到的值;”梯度下降法” = 求最优梯度值使损失函数最小的算法。
- 梯度经典语录:
- 对函数求导得到的值就是梯度(数值理解);没有点就无法求导。
- 梯度就是上山下山最快的方向(方向理解)。
- 在平面内,梯度就是某一点的斜率。
- 反向传播传播的是梯度(利用链式法则从后向前求导)。
- 链式法则中梯度相乘,就是传说中的梯度传播。
- 训练中最常用算法是反向传播:参数根据损失函数关于参数的梯度进行调整;
torch.autograd支持任意计算图的自动梯度计算。 - 三个关键规则:
- PyTorch 不支持向量张量对向量张量求导,只支持标量张量对向量张量求导(y 必须是标量,向量需
y.sum()后 backward)。 - 计算梯度:
y.backward()(y 是标量);获取梯度:x.grad,grad 会累加上一次梯度值(默认累加,需手动清零)。 requires_grad=True才自动计算梯度并保存到 grad 中(默认为 False)。
- PyTorch 不支持向量张量对向量张量求导,只支持标量张量对向量张量求导(y 必须是标量,向量需
- 梯度下降更新公式:
w = w - r * grad(r 是学习率);必须用x.data = x.data - 0.01 * x.grad更新(直接x = x - 0.01*x.grad会新建变量、破坏计算图)。 - 梯度清零:
x.grad.zero_()(注意判断 grad 是否为 None)。 - 注意点:不能将需要自动微分的张量转 numpy(报错 RuntimeError),需用
detach()生成一个共享数据但不自动微分的新张量(x2 = x1.detach(),x2.requires_grad=False,数据与 x1 共享同一内存)。
代码模式(梯度下降求最优解 y=x²+20 的极小值,迭代 1000 次):
x = torch.tensor(10, requires_grad=True, dtype=torch.float32)
y = x ** 2 + 20
for i in range(1, 1001):
y = x ** 2 + 20 # 3-1 前向传播
if x.grad is not None:
x.grad.zero_() # 3-2 梯度清零(默认累加)
y.sum().backward() # 3-3 反向传播
x.data = x.data - 0.01 * x.grad # 3-4 梯度更新 W=W-lr*grad
结果:x 从 10 收敛到 ≈0,y 最小值 ≈20。
自动微分应用(手写单层网络):
x = torch.ones(2, 5); y = torch.zeros(2, 3)
w = torch.randn(5, 3, requires_grad=True); b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w) + b
loss = torch.nn.MSELoss()(z, y)
loss.backward() # 梯度保存在 w.grad / b.grad
2.4 构建线性回归模型(完整流程,重要)
PyTorch 构建模型四步流程:① 准备训练集数据 → ② 构建模型 → ③ 设置损失函数和优化器 → ④ 模型训练。
API 对照:nn.MSELoss() 代替平方损失;data.DataLoader 代替数据加载器;optim.SGD 代替优化器;nn.Linear 代替假设函数。
import torch
from torch.utils.data import TensorDataset, DataLoader
from torch import nn, optim
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt
def create_dataset():
x, y, coef = make_regression(n_samples=100, n_features=1, noise=10,
coef=True, bias=14.5, random_state=0)
return torch.tensor(x), torch.tensor(y), coef
def train():
x, y, coef = create_dataset()
dataset = TensorDataset(x, y)
dataloader = DataLoader(dataset=dataset, batch_size=16, shuffle=True) # 数据加载器
model = nn.Linear(in_features=1, out_features=1) # 假设函数(含 w、b)
criterion = nn.MSELoss() # 平方损失
optimizer = optim.SGD(params=model.parameters(), lr=1e-2) # 优化器
epochs = 100
epoch_loss, total_loss, train_sample = [], 0.0, 0.0
for _ in range(epochs):
for train_x, train_y in dataloader:
y_pred = model(train_x.type(torch.float32)) # 送入模型
loss = criterion(y_pred, train_y.reshape(-1, 1).type(torch.float32))
total_loss += loss.item(); train_sample += 1
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播
optimizer.step() # 参数更新
epoch_loss.append(total_loss / train_sample)
# 绘制损失变化曲线 + 拟合直线(训练线 vs 真实线 y = coef*x + 14.5)
要点:in_features/out_features 是输入/输出张量第二维大小;model.weight、model.bias 可查看参数;train_y 需 reshape(-1,1) 与预测值形状对齐并统一 dtype。
2.5 PyTorch 常用 API 速查与易考点
- 构建模型:继承
nn.Module,__init__里定义层,forward里定义前向传播(调用模型对象时自动执行)。 - 训练四件套:
optimizer.zero_grad()→loss.backward()→optimizer.step()(顺序固定)。 - 数据流:
Dataset(TensorDataset)→DataLoader(batch_size=, shuffle=)→ for 循环取 batch。 - 模型保存/加载:
torch.save(model.state_dict(), 'xxx.pth');model.load_state_dict(torch.load('xxx.pth'))。 - 训练/推理模式:
model.train()/model.eval()(影响 Dropout/BN)。 - 易考点:动态图 vs 静态图;
tensor.numpy()与from_numpy共享内存;带下划线运算符就地修改;view要求连续内存;detach()用途;自动微分只支持标量对向量求导、梯度默认累加;为什么用x.data更新而非x = x - lr*grad。
三、神经网络基础
3.1 神经网络概念
- 人工神经网络(ANN/NN):模仿生物神经网络结构和功能的计算模型,由多个互相连接的人工神经元(节点)构成,用于处理和学习复杂数据模式,尤其适合解决非线性问题。
- 生物类比:树突接收输入信号 → 细胞核聚集电荷 → 达到电位激活 → 轴突输出信号;人工神经元即”加权求和 + 激活函数”。
- 神经网络结构三部分:
- 输入层:输入 x 的那一层,每个输入特征对应一个神经元。
- 输出层:输出 y 的那一层,按任务(回归/分类)生成预测结果。
- 隐藏层:输入层与输出层之间,网络的”深度”由隐藏层数量决定。
- 全连接神经网络(FCNN)特点:同一层神经元之间无连接;第 N 层每个神经元与第 N-1 层所有神经元相连(Fully Connected 的含义);接收的样本数据是二维的,数据在层间以二维形式传递;第 N-1 层输出就是第 N 层输入;每个连接有权重(w 和 b)。
- 同一层的多个神经元并行处理相同输入,学习输入数据的不同特征。
3.2 神经元内部状态值与激活值
- 前向传播:数据从输入到输出经过一层层神经元产生预测值的过程。每个神经元前向产生两个值:
- 内部状态值(加权求和值):
z = w·x + b(w 权重矩阵、x 输入、b 偏置)。 - 激活值:
a = f(z)(f 为激活函数)。
- 内部状态值(加权求和值):
- 反向传播时产生激活值梯度与内部状态值梯度。
- 控制每层内部状态值、激活值的方差可使网络工作得更好(引出激活函数与权重初始化)。
3.3 激活函数
3.3.1 为什么需要激活函数
- 没有引入非线性因素的网络等价于线性模型,无法拟合复杂曲线;
- 通过给网络输出增加激活函数引入非线性因素,使网络可以逼近任意函数,提升对复杂问题的拟合能力;
- 反向传播(BP)要求激活函数必须可微。
3.3.2 Sigmoid
- 公式:
f(x) = 1 / (1 + e^(-x));导数:f'(x) = f(x)·(1 - f(x)),导数值域 (0, 0.25)。 - 将任意输入映射到 (0, 1);输入在 [-6, 6] 之间输出才有明显差异,[-3, 3] 之间效果较好;输入 <-6 或 >6 时激活值几乎相同(如输入 100 和 10000 激活值都≈1,丢失相差 100 倍的信息)。
- 导数在 |x|>6 时接近 0 → 网络参数更新极其缓慢或无法更新。
- 缺点:
- 梯度消失:一般 sigmoid 网络 5 层之内就产生梯度消失(0.25^n 连乘)。
- 输出不以 0 为中心(恒为正),梯度更新只对某些特征产生同方向影响。
- 使用场景:一般只用于二分类的输出层。
- PyTorch:
torch.sigmoid(x)。
3.3.3 Tanh(双曲正切)
- 公式:
f(x) = (e^x - e^(-x)) / (e^x + e^(-x));导数:f'(x) = 1 - f(x)²,导数值域 (0, 1)。 - 将输入映射到 (-1, 1),以 0 为中心、0 点对称,可学习正负信号。
- 与 Sigmoid 相比:以 0 为中心、梯度相对更大,收敛速度更快、迭代次数更少;但两侧导数也为 0,同样会造成梯度消失(输入 |x|>3 时导数≈0)。
- 使用建议:隐藏层用 tanh,输出层用 sigmoid。
- PyTorch:
torch.tanh(x)。
3.3.4 ReLU
- 公式:
f(x) = max(0, x);导数:x>0 时为 1,x<0 时为 0(x=0 处不可导,一般取 0 或 1)。 - 将小于 0 的值映射为 0,大于 0 的值保持不变:更重视正信号、忽略负信号;运算简单,提高训练效率。
- 优点(与 sigmoid 相比,高频考点”ReLU 为什么好”):
- 计算量小:sigmoid 含指数运算,反向传播求梯度计算量大;ReLU 整个计算量节省很多。
- 缓解梯度消失:x>0 时梯度恒为 1,梯度不衰减,不会出现 sigmoid 那样的梯度消失,可训练深层网络。
- 稀疏性:使一部分神经元输出为 0,造成网络稀疏,减少参数相互依存,缓解过拟合。
- 缺点:神经元死亡(Dead ReLU)——随着训练推进,部分输入落入 <0 区域,导数恒为 0,对应权重无法更新。
- 使用:目前最常用的激活函数。
- PyTorch:
torch.relu(x);变体有torch.leaky_relu()、torch.prelu()(Leaky ReLU / PReLU)。
3.3.5 Softmax
- 用于多分类,是 sigmoid 在多分类上的推广;把网络输出的 logits 映射成 (0,1) 的概率,且所有值累和为 1(满足概率性质),取概率最大的节点作为预测类别。
- 公式:
p_i = e^(z_i) / Σ_j e^(z_j)。 - PyTorch:
torch.softmax(scores, dim=0)(dim=0 按行计算;dim=-1 每行数据相加为 1)。 - 示例:scores=[0.2,0.02,0.15,0.15,1.3,0.5,0.06,1.1,0.05,3.75] → softmax 后最大概率 0.7392(对应 3.75)。
3.3.6 激活函数选择
- 隐藏层:优先 ReLU;效果不好换 Leaky ReLU 等;用 ReLU 注意 Dead ReLU 问题;少用 sigmoid,可用 tanh。
- 输出层:二分类 → sigmoid;多分类 → softmax;回归 → identity(恒等)。
3.4 参数初始化
- 需要初始化的参数:权重和偏置(偏置一般初始化为 0 即可)。
- 参数初始化三大作用:① 防止梯度消失或爆炸(初始权重过大/过小导致梯度指数级增大/缩小);② 提高收敛速度(激活值分布适中,梯度高效更新);③ 打破对称性(否则所有神经元更新方向相同,学习能力受限)。
| 初始化方法 | 公式/规则 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 随机初始化(均匀) | 默认区间 (0,1),可设为 (-1/√d, 1/√d),d=输入数量 | 能有效打破对称性 | 范围不当可能导致梯度问题 | 浅层网络(隐藏层 1–3 层、总层数≤5) |
| 随机初始化(正态) | 均值 0、标准差 1 的高斯分布取小值 | 同上 | 同上 | 同上 |
| 全 0 初始化 | 所有权重为 0 | 实现简单 | 无法打破对称性,无法有效训练 | 几乎不使用,仅用于偏置初始化 |
| 全 1 初始化 | 所有权重为 1 | 实现简单 | 无法打破对称性;激活值指数增长易梯度爆炸 | 测试/调试、特殊稀疏网络 |
| 固定值初始化 | 所有权重为某个固定值 | 实现简单 | 无法打破对称性;过大/过小导致梯度爆炸/消失 | 测试/调试 |
| kaiming(HE)初始化 | 正态:std=√(2/fan_in);均匀:limit=√(6/fan_in) | 适合 ReLU,保持梯度稳定 | 对非 ReLU 效果一般 | 深度网络(10 层及以上)+ ReLU/Leaky ReLU |
| xavier(Glorot)初始化 | 正态:std=√(2/(fan_in+fan_out));均匀:limit=√(6/(fan_in+fan_out)) | 适用于 Sigmoid/Tanh,解决梯度消失 | 对 ReLU 表现欠佳 | 深度网络(10 层及以上)+ Sigmoid/Tanh |
- 术语:fan_in = 当前层接收的来自上一层的神经元数量(输入个数);fan_out = 当前层传给下一层的神经元数量(输出个数)。
- 选择规则:Sigmoid/Tanh → xavier;ReLU/Leaky ReLU → kaiming;浅层 → 随机初始化;深层 → xavier/kaiming。
- PyTorch 代码:
nn.init.uniform_ / normal_ / constant_ / zeros_ / ones_ / kaiming_normal_(nonlinearity='relu') / kaiming_uniform_ / xavier_normal_ / xavier_uniform_(作用于linear.weight等)。
3.5 神经网络搭建与参数计算
- 在 PyTorch 中定义网络 = 层堆叠:继承
nn.Module,实现两个方法:__init__:定义网络层结构(主要是全连接层)并初始化;forward:调用模型对象时自动执行,为各层传入数据做前向传播。
- 示例模型(3-3-2-2):hidden1 用 xavier + sigmoid,hidden2 用 kaiming + relu,输出层线性 + softmax(dim=-1)。
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = nn.Linear(3, 3)
nn.init.xavier_normal_(self.linear1.weight); nn.init.zeros_(self.linear1.bias)
self.linear2 = nn.Linear(3, 2)
nn.init.kaiming_normal_(self.linear2.weight, nonlinearity='relu'); nn.init.zeros_(self.linear2.bias)
self.out = nn.Linear(2, 2)
def forward(self, x):
x = torch.sigmoid(self.linear1(x))
x = torch.relu(self.linear2(x))
return torch.softmax(self.out(x), dim=-1)
- 数据形状:输入 [batch_size, in_features] → 输出 [batch_size, out_features];例:5×3 输入 → 5×2 输出(softmax 后每行和为 1)。
- 参数数量计算:以第一个隐层为例(3 个输入 → 3 个神经元),每个神经元参数 = w1,w2,w3,b 共 4 个,共 3×4=12 个。三层 (3→3, 3→2, 2→2) 总参数 = 12+8+6 = 26(可用
torchsummary.summary(model, input_size=(3,), batch_size=5)查看)。 - 查看可学习参数:
for name, parameter in model.named_parameters(): print(name, parameter)。 - 注意:输入数据和网络权重是两回事,要分得清。
3.6 损失函数
- 概念:损失函数用来衡量模型参数质量,即比较网络输出(预测值)与真实输出(真实值)的差异;模型通过最小化损失函数调整参数。别名:代价函数、目标函数、误差函数等。
- 作用:① 评估性能;② 指导优化(梯度下降最小化损失)。
3.6.1 分类任务损失(交叉熵)
- 多分类(softmax 损失):
nn.CrossEntropyLoss()= softmax + 损失计算(PyTorch 中直接对网络输出 logits 计算,不需要手动加 softmax 层)。公式:L = -Σ_i y_i·log(S(f(x))_i),其中 y_i 为真实概率、f(x) 为预测分数、S 为 softmax。本质是最小化正确类别预测概率的对数的负值。注意 y_true 必须是 int64 类型;reduction='mean'(默认平均损失)/'sum'(总损失)。 - 二分类:输出层用 sigmoid,损失用
nn.BCELoss(),公式L = -[y·log(ŷ) + (1-y)·log(1-ŷ)],其中 y 为真实概率、ŷ 为预测概率(sigmoid 输出)。
3.6.2 回归任务损失
- MAE(L1 Loss,平均绝对误差):
nn.L1Loss(),以绝对误差作为距离。特点:具有稀疏性,常作为正则项;零点不可导、梯度不平滑,会跳过极小值;对异常值/离群点不敏感(线性惩罚)。 - MSE(L2 Loss,均方误差/欧氏距离):
nn.MSELoss(),误差平方和的均值。特点:任意位置可导,越接近底部导数越小,符合梯度下降套路;对离群点敏感(平方放大误差);预测与目标相差很大时梯度容易爆炸(层间梯度 >1 重复相乘导致指数级增长)。 - Smooth L1:
nn.SmoothL1Loss(),MSE 与 MAE 优点的结合。分段函数:|x|≤1 时为 0.5x²(L2,解决 L1 不光滑),|x|>1 时为 |x|-0.5(L1,解决离群点梯度爆炸)。对离群点更鲁棒、梯度更平滑。常用于目标检测等。
3.7 梯度下降与反向传播
3.7.1 梯度下降算法回顾
- 梯度下降 = 寻找使损失函数最小化的方法;梯度的方向是函数增长最快的方向,梯度的反方向是函数减少最快的方向:
w = w - η·grad。 - 学习率 η:太小 → 收敛慢、训练时间成本增大;太大 → 可能直接跳过最优解、不收敛甚至震荡(梯度爆炸)。解决:学习率随训练变化(学习率衰减)。
- 三个基础概念(高频考点):
- Epoch:使用全部数据对模型进行的一次完整训练(训练轮次)。
- Batch:每次反向传播参数更新使用的小部分样本(每批样本数量)。
- Iteration:使用一个 Batch 数据对模型进行一次参数更新的过程。
- 例:50000 样本、Batch Size=256 → 每 Epoch 训练 50000 张、Batch 个数=50000/256+1=196(未整除 +1)、每 Epoch Iteration=196、10 Epoch Iteration=1960。
- 梯度下降三种方式的根本区别在 Batch Size:BGD(全部样本,计算量大)、SGD(随机一个样本,梯度可能不合理)、Mini-Batch(一批样本,计算量相对小、梯度更合理)。
3.7.2 反向传播(BP 算法)
- 前向传播:数据输入网络,逐层向前传输,一直运算到输出层,得到预测值与真实值的误差 ERROR。
- 反向传播:利用损失函数 ERROR,从后往前,结合梯度下降算法,依次求各参数的偏导(梯度),并更新参数。
- 核心:利用链式法则对神经网络各节点权重求梯度(如求 E 对 w5 的导数 = ∂E/∂out_o1 · ∂out_o1/∂net_o1 · ∂net_o1/∂w5;求 w1 时路径不止一条,各路径梯度相加)。“反向传播传播的是梯度”。
- BP 算法不仅可用于多层前馈神经网络,也可用于其他类型网络;通常”BP 网络”指用 BP 算法训练的多层前馈网络。
3.7.3 梯度下降优化方法(重要对比)
- 梯度下降可能遇到的问题:平缓区域(梯度小,优化变慢)、鞍点(梯度为 0,参数无法优化)、局部最小值(参数非最优)。
- 优化方法:Momentum、AdaGrad、RMSprop、Adam。
① 指数移动加权平均(EWA,基础)
- 公式:
S_t = β·S_(t-1) + (1-β)·Y_t(S_t 指数加权平均值、Y_t 当前时刻值、β 权重系数)。 - β 越大曲线越平缓(当前值影响越小),β 一般默认 0.9;用途:气温平滑曲线。
② Momentum(动量法)
- 梯度公式:
s_t = β·s_(t-1) + (1-β)·g_t;参数更新:w_t = w_(t-1) - η·s_t。 - 用历史梯度的指数移动加权平均值代替当前梯度:平滑梯度变化,减小震荡,加快收敛;处于鞍点(当前梯度为 0)时因已积累历史梯度,可能跨过鞍点。
- PyTorch:
optim.SGD([w], lr=0.01, momentum=0.9)。
③ AdaGrad
- 对不同参数分量用不同学习率,总体学习率逐渐减小(初期离目标远用大学习率,后期学习率下降)。
- 步骤:累积平方梯度
s_t = s_(t-1) + g_t⊙g_t;学习率η = η/(√s_t + σ)(σ=1e-10 防除 0);更新w_t = w_(t-1) - η/(√s_t+σ)·g_t。 - 缺点:学习率过早、过量降低,后期学习率太小难找最优解。
- PyTorch:
optim.Adagrad([w], lr=0.01)。
④ RMSProp
- 对 AdaGrad 的优化:用指数加权平均梯度替换历史梯度平方和:
s_t = β·s_(t-1) + (1-β)·g_t⊙g_t。 - 通过衰减系数 β 控制历史梯度信息的多少;避免学习率过早衰减,非凸条件下优化更好、学习率衰减更合理。
- 注意:AdaGrad 和 RMSProp 都是对每个参数分量用不同学习率(梯度大的分量学习率小,反之大)。
- PyTorch:
optim.RMSprop([w], lr=0.01, alpha=0.9)(alpha 对应 β)。
⑤ Adam(自适应矩估计)
- = Momentum + RMSProp:用梯度的一阶矩(均值)修正梯度,用梯度平方的二阶矩(方差)修正学习率。
- 公式:
m_t = β1·m_(t-1) + (1-β1)·g_t;s_t = β2·s_(t-1) + (1-β2)·g_t²;偏差校正m̂ = m/(1-β1^t)、ŝ = s/(1-β2^t);更新w_t = w_(t-1) - η/(√ŝ_t + ε)·m̂_t。 - PyTorch:
optim.Adam([w], lr=0.01, betas=[0.9, 0.99])。
优化器选择小结(表):
| 算法 | 优点 | 缺点 | 适用 |
|---|---|---|---|
| SGD | 简单易实现 | 收敛慢、易震荡 | 简单任务、数据分布稳定 |
| Momentum | 加速收敛、减少震荡(高曲率区域) | 需调动量超参数 | 非平稳优化、深度学习 |
| AdaGrad | 自适应学习率,适合稀疏数据 | 学习率过早衰减、早期停滞 | 稀疏数据(NLP、推荐) |
| RMSProp | 解决 AdaGrad 过早衰减,适应性强 | 需选好超参数、可能过于激进 | 动态/非平稳目标 |
| Adam | 结合两者优点,适应性强且稳定 | 超参数多、可能较大波动 | 广泛深度学习任务 |
- 选择口诀:简单任务/小模型 → SGD 或 Momentum;复杂任务/大数据 → Adam;稀疏数据/文本 → AdaGrad 或 RMSProp。
3.8 学习率衰减
- 为什么要衰减:训练后期学习率过高会造成 loss 振荡;减小过慢会造成收敛变慢。理想:前期收敛快、后期收敛慢。
- 实验结论(y=4x²):小学习率下降慢;大学习率越过最小值点导致震荡、甚至不收敛(梯度爆炸);lr=0.125 时一步到最优点。
| 方法 | 公式 | PyTorch API | 特点 |
|---|---|---|---|
| 等间隔衰减 | 每 step_size 轮 lr = lr * gamma | optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5) | 简单直观,适合大批量数据 |
| 指定间隔衰减 | 在指定轮次 lr = lr * gamma | optim.lr_scheduler.MultiStepLR(optimizer, milestones=[50,125,160], gamma=0.5) | 按经验设定关键轮次 |
| 指数衰减 | lr = lr * gamma^epoch | optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95) | 平滑、符合梯度下降规律(前期快中期慢后期更慢) |
- 使用套路:每 epoch 训练完调用
scheduler.step();用scheduler.get_last_lr()查看当前学习率。 - 选择建议:优先指数衰减;按经验用指定间隔;简单模型用等间隔。
3.9 正则化方法
- 正则化定义:为减小测试误差、提高泛化能力而采用的策略统称;神经网络表示能力强、易过拟合,需正则化。常用策略:范数惩罚、Dropout、特殊网络层(BN)等。
3.9.1 Dropout(随机失活)
- 原理:训练时让神经元以超参数 p(丢弃概率)的概率停止工作(激活置为 0),未置 0 的进行缩放,缩放比例 1/(1-p);每次基于输入数据只更新子网络的参数(相当于训练很多子网络的集成)。
- p 取值:通常 0.2–0.5;小模型/复杂任务可 0.3 或更小;很深网络用 0.5/0.6;通常加在全连接层激活函数之后。
- 训练 vs 测试:
- 训练:
model.train(),随机失活并缩放 1/(1-p),使期望输出 E[x_dropout]=[(1-p)·x]/(1-p)=x,与测试期望一致。 - 测试:随机失活不起作用,用所有神经元预测,
model.eval()。
- 训练:
- 作用:防止过拟合(防止预测结果受某个神经元/特征影响过大)。
- 代码:
nn.Dropout(p=0.4);示例输入 [0,1.8033,1.4608,4.5189,6.9116] 失活后出现 0,未失活值 ×1/(1-0.4)。
3.9.2 批量归一化(Batch Normalization, BN)
- 动机:流经网络的每个 batch 数据分布变化剧烈,网络参数频繁大幅调整、难以收敛;对每个 batch 数据标准化(均值≈0、方差≈1)后分布稳定,梯度变化稳定,加速收敛。
- 公式:先标准化
x̂ = (x - E(x)) / √(Var(x) + eps)(eps 通常 1e-5,防除 0),再重构y = λ·x̂ + β(λ、β 是可学习参数,对标准化值做线性变换,λ 为系数、β 为偏置)。 - 步骤:① 在网络层(Conv2d/Linear)之后、激活函数之前添加 BN 层(Conv2d→BN→ReLU 或 Linear→BN→ReLU);② 训练时计算当前 batch 的 μ、σ² 并规范化,同时维护全局均值/方差的移动平均;③ 推理时(
model.eval())用训练阶段的全局均值/方差,不再用当前 batch 统计量。 - 作用(优点):
- 减少内部协方差偏移:输入分布稳定,加速训练、更稳定;
- 加速训练:避免每层输入分布不断变化导致学习慢;
- 起到正则化作用:不同批次统计量引入噪声,减少对其他正则化(如 Dropout)的依赖;
- 提升泛化能力。
- 使用场景:计算机视觉领域使用较多。
- 类别:
nn.BatchNorm1d(全连接/一维,输入 (N, num_features))、nn.BatchNorm2d(CNN 图像,(N,C,H,W),对每个通道的特征图标准化)、nn.BatchNorm3d(3D CNN/视频,(N,C,D,H,W))。参数:num_features(通道数/特征数)、eps、momentum、affine(默认 True,使用可学习 γ、β)。 - 注意:BatchNorm1d 要求每批样本至少 2 个,否则无法统计均值和方差。
3.9.3 正则化小结(课堂笔记补充)
- L1 正则:需要手动写代码实现;L2 正则:
SGD(weight_decay=...);此外还有 dropout、BN。(具体 L1/L2 公式资料未展开。)
3.10 神经网络优缺点(PPT)
- 优点:精度高,性能优于其他机器学习方法甚至某些领域超过人类;可近似任意非线性函数;框架和库多。
- 缺点:黑箱难解释;训练时间长、需大量算力;结构复杂、需调超参数;小数据集上表现不佳、易过拟合。
3.11 综合案例:手机价格分类(FCN 全连接网络)
- 需求:根据 20 个手机性能特征预测价格区间(0/1/2/3 四类)→ 分类问题。
- 数据:共 2000 条,1600 训练 / 400 测试(
train_test_split(x, y, train_size=0.8, random_state=88));特征数 20、类别数 4。 - 模型:3 个全连接层 20→128→256→4,ReLU 激活(输出层不做 softmax,因为
nn.CrossEntropyLoss内含 softmax)。 - 训练:
CrossEntropyLoss+optim.SGD(lr=1e-3),batch_size=8,50 epochs,torch.manual_seed(0);保存torch.save(model.state_dict(), 'model/phone-price-model.pth')。 - 评估:加载权重 →
model.eval()→torch.argmax(output, dim=1)取类别 →Acc = correct / len(valid_dataset)。初始 Acc: 0.64250。 - 性能优化手段(高频考点):① 数据标准化(StandardScaler);② 优化方法 SGD→Adam;③ 学习率 1e-3→1e-4;④ 增加网络深度/参数量(20→128→256→512→128→4);⑤ 增加 BN 层;⑥ 增加训练轮数等。
四、卷积神经网络 CNN
4.1 图像基础知识
- 图像由像素点组成,像素值范围 [0, 255]:越接近 0 越暗(黑),越接近 255 越亮(白)。
- 四种图像类型:
- 二值图像:1 通道,取值 0/1(0 黑 1 白),用于 OCR、掩膜存储。
- 灰度图像:1 通道,[0,255],8 位无符号整型(int8);二值图像是灰度图像特例。
- 索引图像:1 通道,像素值作索引查颜色索引矩阵 MAP(MAP 大小如 256×3,MAP=[RGB])。
- 真彩色 RGB 图像:3 通道(R、G、B 三个 M×N 二维矩阵),每个像素颜色直接存放,8 位无符号;注意:通道顺序是 BGR 而不是 RGB(OpenCV 惯例,资料原文如此)。
- 深度学习中多用彩色图(RGB 3 通道);图像在 numpy/matplotlib 中形状为 (H, W, C)(高、宽、通道)。
- 加载/显示:
plt.imread("data/img.jpg")、plt.imshow(img)、plt.imsave(...);全 0 数组=黑色图像,全 255=白色(np.zeros([200,200,3])/np.full([200,200,3], 255))。
4.2 CNN 概述
- 定义:卷积神经网络 = 含有卷积层的神经网络,是深度学习在计算机视觉领域的突破性成果,专门处理图像、视频、语音等数据。卷积层的作用是自动学习、提取图像特征。
- 为什么不用全连接网络:图像大时全连接计算代价高,且难以保留原有特征、准确率不高。
- CNN 三大部分:
- 卷积层(CONV):提取图像中的局部特征(线性乘积求和)。
- 池化层(POOL):大幅降低参数量级(降维)(取区域平均值或最大值)。
- 全连接层(FC):类似 ANN 部分,接收二维数据,输出预测结果。
- 经典 CNN 结构流程:数据输入层(去均值/归一化/PCA,CNN 只对训练集做”去均值”)→ [卷积层 CONV → 激励层 ReLU → 池化层 POOL] 重复 → 全连接层 FC 输出。
- 应用:图像分类、目标检测、图像分割、人脸识别、医学图像分析、自动驾驶。
4.3 卷积层(核心)
4.3.1 卷积计算原理
- 卷积运算本质 = 卷积核(滤波器)与输入数据的局部区域做点积(等价于线性层加权求和)。
- 术语:input=输入图像;filter=卷积核/滤波器(滤波矩阵),即一组固定权重的神经元(一个卷积核就是一个神经元),多个滤波器叠加成卷积层;输出=特征图(feature map)。
- 单点计算:
w1x1 + w2x2 + ... + b(w 为卷积核权重,x 为局部像素值)。 - 不同滤波器提取不同特征(颜色深浅、轮廓等),想提取什么特征就用什么滤波器。
4.3.2 Padding(填充)
- 定义:在输入特征图边界周围添加额外像素(通常是 0)。
- 作用:① 保持空间维度(不 padding 特征图不断缩小,边缘信息丢失);② 保留边缘信息(边缘像素参与计算次数少,padding 增加其参与度);③ 提高性能。
- 类型:Valid Padding(不填充,输出缩小)、Same Padding(输出与输入同尺寸)、Full Padding(尽可能多填,输出变大,较少用)。
4.3.3 Stride(步长)
- 定义:卷积核在图像上滑动时的步伐大小(每次移动的像素数)。
- 作用:① 降低计算复杂度(移动次数少);② 步长越大特征图越小(类似池化降维);③ 增大感受野(每个神经元捕捉更大范围输入)。
- 选择:Stride=1 最常见(保留空间细节);Stride=2 或 4 用于快速降维、增大感受野。
4.3.4 多通道卷积
- 卷积核通道数必须与输入图像通道数相同(RGB 三通道 → 每个卷积核也是 3 通道)。
- 每个卷积核通道与输入对应通道卷积,各通道卷积结果按位相加得到最终特征图(1 个二维特征图)。
- 多卷积核:有多少个卷积核(神经元)就提取多少张特征图(从不同视角/角度提取特征)。
4.3.5 特征图尺寸计算(高频考点)
- 输入图像 W×W、卷积核 F×F、Stride=S、Padding=P → 输出 N×N:
N = (W - F + 2P) / S + 1(除不尽则向下取整)。 - 例:5×5 图像、3×3 卷积核、S=1、P=1 → (5-3+2)/1+1 = 5(Same 效果)。
- 卷积核大小一般选奇数(1×1、3×3、5×5)。
4.3.6 PyTorch 卷积层 API
conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
# in_channels: 输入通道数(RGB 为 3)
# out_channels: 输出通道 = 卷积核(神经元)数量
# kernel_size: 卷积核大小,一般 3/5/7
# stride: 步长;可为整数(所有维度相同)或元组 (2,1)
# padding: 四周填充圈数,默认补 0;padding='same'(PyTorch 1.9+) 保持尺寸但 stride 必须为 1;padding=kernel_size-1 为 Full Padding
- 使用流程(图像 → 卷积):读图
plt.imread(H,W,C)→torch.tensor(img).permute(2,0,1)变 (C,H,W) →unsqueeze(0)变 (batch,C,H,W) → 送入卷积层。 - 示例:640×640×3 图,
nn.Conv2d(3, 4, kernel_size=3, stride=2, padding=0)→ 输出 [1, 4, 319, 319]((640-3+0)/2+1=319.5 向下取整 319)。
4.4 池化层
- 作用:对卷积层输出特征图下采样(降维):① 降维、减少计算量和内存;② 提高鲁棒性(对平移、旋转、噪声不敏感);③ 防止过拟合(减少模型复杂度);④ 提取更抽象高层特征。
- 两种方式:
- 最大池化(Max Pooling):取窗口内最大值作为输出。
- 平均池化(Avg Pooling):取窗口内均值作为输出。
- 多通道池化:对每个输入通道分别池化(不像卷积那样相加),所以池化前后通道数不变;池化只在宽高维度进行,通道维度不参与池化。
- API:
nn.MaxPool2d(kernel_size=2, stride=2, padding=1)/nn.AvgPool2d(kernel_size=2, stride=1, padding=0);参数同卷积(kernel_size 为窗口形状,池化层没有神经元参与)。 - 示例:单通道 3×3 输入、kernel=2、stride=1 → 最大池化 [[4,5],[7,8]],平均池化 [[2,3],[5,6]]。
4.5 经典网络架构(按资料内容)
| 网络 | 关键点 | 意义 |
|---|---|---|
| LeNet-5 | 卷积层(提边缘、角点)+ 池化层(子采样,降维+鲁棒)+ 全连接层 | 最早的 CNN 架构之一,证明 CNN 有效性,奠定基础 |
| AlexNet | 更大的卷积核和更多卷积核;ReLU 激活;最大池化;Dropout 防过拟合;全连接分类 | ImageNet 大幅提升准确率,2012 开山之作,推动深度学习发展 |
| VGGNet | 用更小的 3×3 卷积核堆叠增加深度 | 探索深度对性能的影响,深层提取更抽象特征 |
| GoogLeNet (Inception) | Inception 模块:并行不同大小卷积核与池化再拼接 | 提高性能同时减少计算量,增加网络宽度 |
| ResNet | 残差块:跳跃连接(Shortcut),允许梯度直接反向传播到浅层 | 解决深度网络的梯度消失问题,可训练极深网络 |
| DenseNet | 密集块:每层与之前所有层连接(特征重用) | 增强特征传递与梯度流动,避免梯度消失,提高参数效率 |
4.6 CNN 特性小结(易考点)
- 局部连接:每个神经元只与输入的小局部区域(局部感受野)相连,符合图像空间结构,捕捉局部特征。
- 权值共享:同一个卷积核在整个输入上共享权重 → 参数数量大大减少,减少计算量、提高训练效率。
- 平移不变性:卷积是局部的且权重共享 → 物体出现在图像任何位置都能被检测到(空间不变性)。
- 卷积层自动提取特征,无需人工特征工程。
4.7 综合案例:CIFAR10 图像分类(CNN)
- CIFAR-10 数据集:5 万张训练图像 + 1 万张测试图像,10 个类别(airplane/automobile/bird/cat/deer/dog/frog/horse/ship/truck),每类 6k 张,图像大小 32×32×3。加载:
CIFAR10(root='data', train=True, transform=ToTensor())(ToTensor 将 PIL 图像转 Tensor,自动归一化到 [0,1])。 - 网络结构:输入 32×32 → conv1(3→6, k=3) → ReLU → pool1(2×2, s=2)(30→15)→ conv2(6→16, k=3) → ReLU → pool2(2×2, s=2)(13→6)→ 展平 16×6×6=576 → linear1(576→120) → linear2(120→84) → out(84→10)。
- 展平关键代码:
x = x.reshape(x.size(0), -1)(最后一批可能不满 batch_size,不能写死;-1 自动计算 16×6×6=576)。 - 训练:
nn.CrossEntropyLoss()+optim.Adam(model.parameters(), lr=1e-3),batch_size=8,100 epochs;记录 loss、acc。 - 评估:
model.eval()(网络中有 dropout/BN 时评估阶段不执行相应操作);torch.argmax(output, dim=-1) == y统计正确数。 - 结果与过拟合:训练 100 轮训练集 acc≈0.90,测试集 Acc 只有 0.57 → 过拟合。
- 模型优化(考点):学习率 1e-3→1e-4、增加参数量(conv1: 3→32,conv2: 32→128,全连接 576→2048→2048→10)、加 Dropout(p=0.5)(放在激活函数后/全连接层之间)→ 测试集 Acc 提升到 0.93。
五、循环神经网络 RNN
5.1 RNN 概念与应用
- 定义:循环神经网络(RNN)是专门处理序列数据的神经网络;具有”循环”结构,能处理和记住前面时间步的信息,适用于时间序列数据或有时序依赖的任务。
- 序列数据:在不同时间点收集的数据(时间序列);也可以是文字序列。核心特点:后面的数据跟前面的数据有关系。
- 应用场景:NLP(文本生成、语言建模、机器翻译、情感分析);时间序列预测(股市、气象、传感器);语音识别;音乐生成。
- 注意:标准 RNN 难以捕捉长期依赖关系(资料在简介章节明确指出)。
5.2 自然语言处理(NLP)概述
- NLP 研究通过计算机算法理解自然语言(汉语、英语、法语等),该类数据不像结构化数据/图像那样方便数值化。
- NLP 目标:让机器”听懂””读懂”自然语言并进行有效交流分析;涵盖语法分析、语义理解、情感分析、机器翻译等。
5.3 词嵌入层(Word Embedding)
- 作用:把离散单词(词表索引)转换为连续、低维的稠密向量,让网络理解词汇语义;即将文本转换为向量。
- 为什么不用 one-hot:one-hot 是高维稀疏向量,无法反映单词间相似性;词嵌入用低维稠密向量,能捕捉语义相似性(如”猫”与”狗”接近、”猫”与”汽车”遥远)。
- 机制:按词数量构建词向量矩阵(如 100 个词、128 维 → 100×128 矩阵),每个词对应矩阵中一个向量。
- 在 RNN 中的作用:① 输入表示(神经网络不能直接处理离散词索引);② 降低维度(高维稀疏→低维稠密);③ 捕捉语义相似性(训练学习词间关系)。
- 工作流程:初始化词向量(随机或加载预训练 Word2Vec/GloVe)→ 分词、词转索引 → 查词向量 → 送入 RNN。
- PyTorch API:
nn.Embedding(num_embeddings=词的数量, embedding_dim=词向量维度)。用法:jieba 分词 → 去重建词表 →embed(torch.tensor(i))取第 i 个词的向量。
5.4 循环网络层原理(核心公式)
- 文本”我爱你”具有序列关系;RNN 实际是同一个神经元在不同时间步重复使用(展开图里画的 3 个神经元其实是同一个)。
- 隐藏状态 h:保存序列数据中的历史信息并传给下一个时间步。三大作用:记忆功能(跨时间步传递信息)、上下文理解、连接不同时间步(处理变长序列)。
- 每次输入:上一个时间步的隐藏状态 + 当前输入 x;每次输出:当前隐藏状态 + 当前预测 y。
- 文本生成例子:输入”我””爱”预测”你”——初始化 h0(一般全 0)→ 词嵌入”我”送第一个时间步得 h1 → h1+”爱”送第二个时间步得 h2 → h2 送全连接层得”你”的预测概率。
- 计算隐藏状态(RNN 神经元内部):
h_t = tanh(W_ih·x_t + b_ih + W_hh·h_(t-1) + b_hh)- W_ih 输入数据权重、b_ih 输入偏置、W_hh 隐藏状态权重、b_hh 隐藏状态偏置、h_(t-1) 输入隐藏状态、h_t 输出隐藏状态;最后用 tanh 激活。
- 计算当前时刻输出:
y_t = W_hy·h_t + b_y(W_hy 隐藏到输出权重,b_y 输出偏置)。 - 词汇表映射:y_t 是向量,经全连接层得到 y_pred,每个元素是词表中某个词的得分(softmax 转概率);词表有多少个词 y_pred 就有多少个元素,最大元素对应的词就是预测生成的词(本质是分类问题,每个词一个类别)。
- 神经元工作机制总结:接收输入(x_t、h_(t-1))→ 更新隐藏状态 h_t(含过去记忆+当前输入)→ 基于 h_t 生成输出 y_t。
- 文本生成预测流程:输入”m”→x1 → 初始化 h0=0 → 更新 h1 计算 y1 → 全连接+softmax 转概率 → 选概率最高的词(如”a”)→ 把”a”作为下一时间步输入继续,直到生成完整句子。
5.5 PyTorch RNN 层 API
RNN = nn.RNN(input_size, hidden_size, num_layers)
output, hn = RNN(x, h0)
- 参数:
input_size输入维度(一般=词向量维度);hidden_size隐藏层 h 维度(也是神经元输出维度);num_layers隐藏层层数(默认 1)。 - 输入:x 形状 [seq_len, batch, input_size](句长、批量、词向量维度);h0 形状 [num_layers, batch, hidden_size]。
- 输出:output 形状 [seq_len, batch, hidden_size](每个时间步的隐藏状态);hn 形状 [num_layers, batch, hidden_size](最后一层最终隐藏状态)。
- 示例:
rnn = nn.RNN(input_size=128, hidden_size=256);inputs = torch.randn(5, 32, 128)(5 个词、32 个句子);hn = torch.zeros(1, 32, 256)→ output 形状 [5,32,256],hn 形状 [1,32,256]。
5.6 综合案例:周杰伦歌词生成(文本生成)
- 数据集:周杰伦第一张专辑《Jay》到第十张《跨时代》歌词,5819 行文本。
- 任务:输入起始词,逐个预测下一个词,生成指定长度歌词(本质是多分类问题)。
- 实现流程:构建词表 → 构建数据集对象 → 编写网络模型 → 编写训练函数 → 编写预测函数。
- 构建词表:jieba 分词 → 去重得 unique_words → 建 word_to_index 映射 → 全文转索引 corpus_idx(每行词之间加空格索引分隔,消除行间语义关系)。
- 数据集(LyricsDataset):继承
torch.utils.data.Dataset,实现__len__和__getitem__;num_chars个词为一个样本:x=corpus[start:end],y=corpus[start+1:end+1](预测下一个词,y 相对 x 后移一位);句子数=word_count//num_chars。 - 模型(TextGenerator):
nn.Embedding(词数, 128)→nn.RNN(128, 256, 1)→nn.Linear(256, 词数);forward 中注意embed.transpose(0, 1)把 (batch, seq_len, dim) 换成 RNN 要求的 (seq_len, batch, dim);输出 reshape 成 (-1, 256) 送全连接;init_hidden(bs)返回torch.zeros(1, bs, 256)。 - 训练:
nn.CrossEntropyLoss()+optim.Adam(lr=1e-3),num_chars=32、batch_size=5、10 epochs;y 需torch.transpose(y,0,1).reshape(-1)展平成与 output 对齐的一维索引。训练 10 轮 loss 从 1.84 降到 0.096;保存lyrics_model_10.pth。 - 预测:加载模型 →
init_hidden(bs=1)→ 起始词转索引 → 循环:model(torch.tensor([[word_idx]]), hidden)输出 →torch.argmax(output)取概率最大词 → 该词作为下一次输入,直到生成指定长度。示例:predict(‘分手’, 50) 生成的歌词通顺。
5.7 RNN 易考点
- RNN 为什么适合序列数据(隐藏状态记忆);标准 RNN 的长期依赖问题(资料明确提及但未展开讲 LSTM/GRU,LSTM/GRU 门控结构在本资料中未涉及)。
- h_t、y_t 公式;为什么展开图中”3 个神经元其实是 1 个”;隐藏状态的三大作用。
- 词嵌入 vs one-hot;nn.Embedding 两个参数。
- RNN 输入输出形状:x=[seq_len, batch, input_size]、h0=[num_layers, batch, hidden_size]、output=[seq_len, batch, hidden_size]。
- 为什么 forward 中要
embed.transpose(0, 1);为什么 y 要展平成一维;为什么reshape(x.size(0), -1)不能写死 batch 数。 - 文本生成 = 逐词分类(词表大小=类别数),选 softmax 概率最大的词。
六、笔记 day01–day06 实操细节整理
Day01:深度学习简介 + PyTorch 框架 + 张量基础
- 深度学习=机器学习的一类算法,人工神经网络为结构、自动提取特征;特点:自动提取特征、解释性差、大量数据+高性能计算、非线性转换。
- 模型归类:ANN(感知机)、CNN(图像/视频)、RNN(NLP)、Transformer(RNN 衍生出来的)、自编码器等。
- PyTorch:python 第三方包,数据以张量类型存在;可在 GPU/TPU/NPU 上运行;当前更新到 2.5 版本。
- 张量维度认知:0 维=标量、1 维=[1 2 3 4 5]、2 维=[[…],[…]]、3 维…;张量是通过类创建的对象,提供方法和属性。
- 实操踩坑:
torch.tensor(list):Python 列表默认 float32;torch.tensor(np.array)继承 numpy 的 float64;int 标量创建 int 张量。torch.Tensor(2, 3)只给形状时是未初始化内存的垃圾值(不是 0)。torch.IntTensor([2.5, 3.3])自动类型转换(截断为 2、3)。torch.arange左闭右开;torch.linspace左闭右闭,step=(end-start)/(steps-1)。- 随机种子:
torch.manual_seed(seed=66)设置后,initial_seed()显示设置的种子值。 zeros_like/ones_like/full_like按给定张量的形状创建。- 类型转换:
t1.type(dtype=torch.FloatTensor)或t1.int()/float()/double()/half()。 tensor.numpy()共享内存(改 numpy 张量也变),torch.from_numpy()也共享;torch.tensor(ndarray)不共享;需要独立用.copy()。.item():只要张量是单个元素(标量/一维/二维均可)就能取出数值。- 带下划线
neg_()等就地修改原张量;点乘*/mul要求形状相同;矩阵乘法@/matmul遵循 (n,m)×(m,p)→(n,p)。 mean(dim=0)按列、dim=1按行;mean 要求浮点类型。
Day02:张量索引、形状操作、拼接、自动微分
- 索引:下标从 0 开始(右到左 -1);
data[行, 列];列表索引data[[1,3],[2,4]]取对应位置元素;布尔索引data[data[:,1]>6];切片data[::2, 1::2];三维data2[0,:,:]等。 - 形状操作:
reshape可用-1自动计算((5,6)→(-1,3) → (10,3));squeeze删除值为 1 的维度((3,1,2,1)→(3,2),指定 dim=1 →(3,2,1),维度值不为 1 不生效);unsqueeze(dim=-1)在最后加一维;permute一次交换任意维顺序;transpose/permute 后张量不连续(is_contiguous()=False),view会报错,需先.contiguous();reshape对连续/非连续都可用。 - 拼接:
cat不改变维度数(指定维数值相加,其他维必须相同);stack新增一个维度(维度值=张量个数),所有张量形状必须相同。 - 自动微分(重点实操):
requires_grad=True且元素类型必须是浮点;loss 必须是标量(loss.sum().backward())。- 梯度默认累加(上次+本次),更新前要
w.grad.zero_()。 - 更新必须
w.data = w.data - 0.01 * w.grad;直接w = w - ...会创建新张量导致问题。 - 自动微分张量不能直接
.numpy(),用w.detach()剥离(共享数据、不自动微分)后再转。 - 应用:
y_pred = torch.matmul(x, w) + b→nn.MSELoss()→loss.sum().backward()→ 看w.grad、b.grad。
Day03:线性回归案例 + 神经网络概念 + 激活函数 + 参数初始化
- 线性回归实操(make_regression 生成 100 个样本、1 特征、noise=10、bias=14.5):
TensorDataset(x, y)构建数据集;DataLoader(batch_size=16, shuffle=True)分批。nn.Linear(1, 1)含随机初始化的 w、b(model.weight、model.bias、list(model.parameters()))。- 踩坑 1:
train_x是 float64,模型 w 是 float32,需train_x.type(torch.float32),否则类型不匹配报错。 - 踩坑 2:
train_y是一维,需reshape(-1, 1)成二维与 y_pred 对齐。 - 训练循环:y_pred → loss(MSE)→ zero_grad → backward → step;100 epochs 后 w、b 逼近真实 coef、14.5;绘制损失曲线与拟合直线(训练线 vs 真实线)。
- 激活函数实操结论:
- sigmoid:激活值范围 [0,1] 只有正信号;加权求和值在 [-6,6] 激活值才有差异(否则 0 或 1);导数范围 [0, 0.25],连乘 0.25×0.25×… 导致梯度消失;一般只在二分类输出层用,隐藏层 5 层内可考虑。
- tanh:范围 [-1,1]、以 0 对称、有正负信号;加权求和值在 [-3,3] 导数才大,否则梯度消失;收敛比 sigmoid 快;隐藏层可用,浅层网络使用。
- relu:范围 [0,x] 只有正信号;导数 0 或 1,线性输出大于 0 时导数为 1 不梯度消失、收敛最快;小于 0 神经元死亡(防过拟合),可换 leaky relu/prelu;优先选择、计算复杂度最小。
- softmax:多分类输出层把加权求和值转概率(
torch.softmax(y, dim=1),dim=-1 按行)。 - 绘图技巧:
torch.linspace(-20, 20, 1000, requires_grad=True)+torch.sigmoid(x).sum().backward()用 autograd 画导数图像(x.detach().numpy() 与 x.grad)。
- 参数初始化实操:
nn.init.uniform_(linear.weight, a=-1/sqrt(5), b=1/sqrt(5))均匀区间可按 a/b 调整;正态nn.init.normal_;其余 zeros/ones/constant/kaiming/xavier_。 - 结论:浅层网络随机初始化;深层网络 tanh→xavier、relu→kaiming。
Day04:网络搭建 + 损失函数 + 优化方法 + 学习率衰减
- nn.Module 搭建(ModelDemo):
super().__init__()→ 定义self.linear1/linear2/output(nn.Linear)→ 在__init__里用nn.init.xavier_normal_(self.linear1.weight)、nn.init.kaiming_normal_(self.linear2.weight, nonlinearity='relu')初始化 →forward里 sigmoid/relu/softmax(dim=-1);调用my_model(data)即执行 forward;summary(model, input_size=(5,3))统计参数;named_parameters()查看各层 w/b。 - 损失函数实操:
- 多分类:
nn.CrossEntropyLoss(reduction='sum'),y_true 用类别索引(int64),y_pred 为 logits;reduction 默认 mean(平均损失),可改 sum(总损失)。 - 二分类:
nn.BCELoss(),y_pred 必须是 sigmoid 输出(概率)。 - 回归:
nn.L1Loss()(MAE,导数为 ±1、0 点不可导)、nn.MSELoss()(MSE,任意位置可导、越接近底部导数越小;有异常样本会放大误差易梯度爆炸)、nn.SmoothL1Loss()(MAE 与 MSE 中和:|w|>1 用 MAE、[-1,1] 用 MSE,不受异常值影响、任意位置可导)。
- 多分类:
- 优化方法实操结论:
- 指数加权平均:S100 = 0.1·Y100 + 0.1·0.9·Y99 + 0.1·0.9²·Y98 + …;β 越大受当前真实值影响越小,一般 0.9。
- Momentum:
optim.SGD([w], lr=0.01, momentum=0.9),计算的是当前时刻的指数移动加权平均梯度。 - AdaGrad:
optim.Adagrad([w], lr=0.01),学习率随训练次数越来越小(初期大后期小)。 - RMSProp:
optim.RMSprop([w], lr=0.01, alpha=0.9),对 adagrad 优化,用指数移动加权平均梯度代替历史累加梯度,避免学习率过快减小。 - Adam:
optim.Adam([w], lr=0.01, betas=(0.9, 0.99)),既优化学习率又优化梯度 = rmsprop + momentum。 - 选择:SGD/momentum 用于简单任务或浅层模型;Adam 用于复杂任务或数据量大;AdaGrad/RMSProp 用于文本数据(NLP)。
- 学习率衰减实操:
- 等间隔:
optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5),每 50 轮 lr=lr*0.5。 - 指定间隔:
optim.lr_scheduler.MultiStepLR(optimizer, milestones=[50,100,160], gamma=0.5, last_epoch=-1),在指定轮次衰减。 - 指数:
optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9),lr=lr*gamma^epoch,更符合梯度下降规律(前期下降快中期慢后期更慢)。 - 每轮训练完调
scheduler.step();用get_last_lr()取当前学习率;选择:优先指数、其次指定间隔、简单模型等间隔。
- 等间隔:
Day05:正则化 + 手机价格分类 + 图像基础 + CNN 卷积/池化
- 正则化结论:防止过拟合(训练集好测试集差)、提高泛化能力;L1 正则需手动写代码实现,L2 正则用
SGD(weight_decay=);此外有 dropout、BN。 - Dropout 实操:
nn.Dropout(p=0.4)放在激活函数之后;每批次随机失活的神经元都不同,防止某个特征影响过大;不失活神经元 ÷(1-p),使训练与测试期望一致;训练model.train()、测试model.eval();p 取值 [0.2,0.5],简单模型概率低、复杂模型概率高。 - BN 实操:计算每个 batch 的均值与标准差做标准化;不同 batch 统计量不同会引入噪声(防过拟合);可学习 γ、β 让每层分布不同;标准化后加权求和值落入激活函数合理区间(导数最大)加速收敛;训练时标准化、测试时不标准化;
nn.BatchNorm1d(一维样本,每批样本最少 2 个)、nn.BatchNorm2d(图像,按每通道二维矩阵计算)、nn.BatchNorm3d(视频);参数 num_features/eps/momentum/affine。 - 手机价格分类:20 特征、4 类别;train_test_split(0.8, random_state=88);df 数据需
.values取 numpy 再torch.tensor转张量;模型 20→128→256→4(输出层不做 softmax,CrossEntropyLoss 内含);optim.SGD(lr=1e-3)、batch=8、50 epochs;评估model.eval()+torch.argmax(output, dim=1)+(y_pred==y).sum()/len(valid);优化手段:数据标准化、加深加宽网络、SGD→Adam、lr 1e-3→1e-4、正则化、增加轮数。 - 图像基础:二值(1 通道 0/1)、灰度(1 通道 0-255)、索引(1 通道索引查 MAP)、RGB 真彩色(3 通道)四类;全黑/全白图
np.zeros/np.full((200,200,3));plt.imread/imsave/imshow;一张 200×200×3 的图放到全连接层就是 120000 个特征的一维向量(说明为什么需要卷积降维)。 - 卷积层实操:卷积计算 = 带权重的卷积核与图像特征值点乘(w1x1+w2x2+…+b),卷积核=带权重参数的神经元;Padding 作用:保持形状一致、减少边缘信息丢失(未 padding 边缘只参与一次计算);Stride 默认 1(可 2/4),5×5 stride=1→3×3、stride=2→2×2;多通道卷积:卷积核通道数与图像通道数一致,各通道卷积结果加和得到新特征图的一个特征值(新特征图是 1 个二维矩阵);多卷积核 = 多少个神经元就提取多少张二维特征图;特征图公式
N=(W-F+2P)/S+1(小数向下取整);APInn.Conv2d(in_channels=3, out_channels=4, kernel_size=(3,3), stride=2, padding=0),图像先permute(2,0,1)变 (C,H,W) 再unsqueeze(0)变 (1,C,H,W)。 - 池化层实操:池化层没有神经元参与、只降维不提取特征;最大池化取窗口最大值、平均池化取均值;多通道池化各通道分别处理、通道数不变(只在高宽维度池化);
nn.MaxPool2d(kernel_size=(2,2), stride=1, padding=0)、nn.AvgPool2d(...)。
Day06:CIFAR10 图像分类 + RNN 词嵌入 + 文本生成
- CIFAR10 实操:torchvision 提供;训练 5 万、测试 1 万、10 类、单图 (32,32,3);
CIFAR10(root='./data', train=True, transform=ToTensor());class_to_idx查看类别映射;data.shape、targets。 - ImageModel 结构:conv1(3→6,k=3) → relu → pool1(2×2,s=2) → conv2(6→16,k=3) → relu → pool2 → linear1(16*6*6=576→120) → linear2(120→84) → out(84→10);展平
x.reshape(x.shape[0], -1)(最后一批不满 batch 不能写死)。 - 训练:CrossEntropyLoss + Adam(1e-3),batch=8、10 epochs;
model.train();统计total_loss += loss.item()*len(y)、total_correct += (torch.argmax(output, dim=-1)==y).sum();打印每轮 loss/acc/time;保存 state_dict。 - 评估:
model.eval();argmax dim=-1 取类别;Acc = correct/total。 - 性能优化(过拟合):增加卷积核数量(3→32、6→128)、增加全连接神经元(2048)、减小学习率、加 Dropout(p=0.5)(训练集 acc 远高于测试集说明过拟合)。
- RNN 部分:词嵌入
nn.Embedding(num_embeddings=词数量, embedding_dim=8),先 jieba 分词再查向量;RNN 层nn.RNN(input_size=128, hidden_size=256, num_layers=1),x 形状 (5,32,128)(每句词数, 句子数, 词向量维度)、h0 (1,32,256)(层数, 句子数, 隐藏维度);h1 = relu(wh0+b+wx+b)、y1 = wh1+b(课堂笔记简化写法,正式公式为 tanh + W_hy·h_t + b_y);多层 RNN 做生成式 AI 只取最后一层隐藏状态与预测输出。 - 歌词生成完整流程:
- build_vocab:jieba.lcut 分词 → 去重 unique_words → word_to_index → corpus_idx(行间插入空格索引分隔)。
- LyricsDataset:
__len__返回 word_count//num_chars;__getitem__返回 x=corpus[start:end]、y=corpus[start+1:end+1](-1 是因为 y 要后移一位)。 - TextGenerator:Embedding(词数,128) → RNN(128,256,1) → Linear(256,词数);
embed.transpose(0,1)调整维度送 RNN;init_hidden(bs)返回 zeros(1,bs,256)。 - 训练:CrossEntropyLoss + Adam(1e-3),num_chars=32、batch_size=5、10 epochs;y 先
torch.transpose(y,0,1)再reshape(-1)与 output(seq_len*batch, 词数) 对齐;loss 从 ~1.84 降至 ~0.096。 - 预测:
predict('分手', 50),循环 argmax 取概率最大词索引作为下一输入,逐个生成。
七、大模型基础
7.1 语言模型
- 定义:语言模型(Language Model)旨在建模词汇序列的生成概率;通俗理解就是计算一个句子概率的模型(判断一句话是否”像人话”)。
- 标准定义:对句子 S=[W1,W2,…,Wn],语言模型计算 P(S);符合语用习惯的句子概率高。
- 例:P(中国的首都是北京) > P(中国的首都是深圳)。
- 概率链式法则:
P(S) = P(W1)·P(W2|W1)·...·P(Wn|W1,...,W(n-1))。 - 简化理解:语言模型 = 计算一个句子的概率,或预测下一个”词”的模型。
7.2 语言模型发展四阶段
- 统计语言模型:统计学方法建模(N-gram)。
- 神经语言模型:简单浅层神经网络计算。
- 预训练语言模型:深层神经网络 + 大量无监督数据。
- 大语言模型:更大更深的网络 + 海量数据 + 预训练加多种后训练。
7.2.1 统计语言模型(N-gram)
- 依据前面 N 个词预测下一个词;常见 1-gram、2-gram、3-gram;引入马尔科夫假设:一个词出现的概率只与它前面有限的几个词有关。
- 1-gram(unigram):词与周围词独立,
P(S)=P(W1)P(W2)...P(Wn);过于简单。 - 2-gram(bigram):词仅依赖前一个词,
P(S)=P(W1)P(W2|W1)...P(Wn|W(n-1));P(Wt|W(t-1)) = C(W(t-1),Wt)/C(W(t-1))(出现次数比)。 - 3-gram(trigram):依赖前两个词,
P(Wi|W(i-1),W(i-2)) = C(W(i-2)W(i-1)Wi)/C(W(i-2)W(i-1))。 - bigram 例子:P(想|我)=C(我,想)/C(我)=800/2100≈0.38;P(我想去打篮球)=P(想|我)·P(去|想)·P(打|去)·P(篮球|打)≈0.0022 > P(我想去打晚饭)≈0.00022 → 预测 [MASK]=篮球。
- 两个缺陷:① 参数空间过大(可能性太多无法估算);② 数据稀疏严重(许多词对组合语料中没出现,最大似然估计概率为 0)。
7.2.2 神经语言模型
- 结构:输入层 = 前 n-1 个词的词向量 C(w) 首尾拼接成 (n-1)·m 维向量 x → 隐藏层全连接 + tanh 激活 → 输出层 V 个节点(V=词汇量,全连接),y_i 表示下一个词为 i 的未归一化 log 概率 → softmax 归一化 → 取最大概率为预测。
- 优点:神经网络建模当前词与前 n-1 个词的约束关系,泛化能力比 n-gram 好,词表征好可大幅降低数据稀疏问题。
- 缺点:对长序列建模能力有限,可能出现长距离遗忘以及训练时梯度消失,难以稳定长文本输出。
7.2.3 预训练语言模型
- Transformer 由编码器和解码器层组成,学习复杂语义能力强;主流预训练模型(GPT、BERT、T5)都用 Transformer 提取特征。
- 使用方式:① 预训练:先在基础数据集/语料库上训练(无监督数据训练),学习数据普遍特征,构建基础模型(初始化参数);② 微调(Fine-tuning):在下游任务用预训练模型做迁移学习。
- 优点:更强大的泛化能力、丰富语义表示、有效防止过拟合;缺点:计算资源需求大、可解释性差。
7.2.4 大语言模型
- 扩展法则(Scaling Law):通过规模扩展(增加参数规模或数据规模)通常带来下游任务性能提升;预训练模型参数指数级提升,语言模型性能线性上升。
- 里程碑:2020 年 OpenAI 发布 GPT-3(1750 亿参数),首次展示大语言模型性能;对比:BERT-large 3.3 亿参数、GPT-2 17 亿参数。
- 涌现能力:大模型具有而小模型不具有的能力(如 GPT-3 的上下文学习 In-Context Learning, ICL,可用少样本数据解决下游任务,GPT-2 不具备)。
- 大语言模型特点:优点——具备一定智能、捕捉上下文语义、强大生成能力(文字/多模态)、可用插件自动信息检索;缺点——参数量大、算力要求高、可能生成有害/有偏见内容。
7.3 语言模型的评估指标
- 生成类任务无确定答案,评估更复杂;开放领域有通用评测任务和数据集,垂直领域可能需自定标准。三个指标:BLEU、ROUGE、PPL。
7.3.1 BLEU(双语评估,机器翻译质量)
- 思想:把”质量”定义为与人类翻译结果(reference)的一致性程度;分数范围 0~1,越接近 1 翻译质量越高。
- 按 n-gram 分 BLEU-1~BLEU-4:BLEU-1 衡量单词级准确性,高阶衡量句子流畅性;实践中取 N=1~4 加权平均(权重默认各 0.25)。
- 计算:匹配的 n-gram 个数 / candidate 中 n-gram 个数(基于精确率)。
- 例:candidate “it is a nice day today” vs reference “today is a nice day”:1-gram 匹配 5/6、2-gram 3/5、3-gram 2/4、4-gram 1/3。
- 综合公式:
BLEU = bp · exp(Σ_(i=1..4) w_i·log(p_i))(bp 为长度惩罚系数,w_i 默认 0.25)。 - 改进(防作弊):极端情况 candidate “the the the the” 按 1-gram 匹配度为 1 不合理 → 用词在译文中出现的最小次数
count_k = min(c_k, s_k)(c_k 在 candidate 出现次数、s_k 在 reference 出现次数),修正后 BLEU1=1/4。 - 代码:
from nltk.translate.bleu_score import sentence_bleu;sentence_bleu(reference, candidate, weights=(0.25,0.25,0.25,0.25))。
7.3.2 ROUGE(摘要/问答评估)
- ROUGE 分 ROUGE-N、ROUGE-L、ROUGE-W、ROUGE-S 四种;与 BLEU 类似,但 ROUGE 基于召回率,BLEU 更看重精确率。
- ROUGE-N:匹配的 n-gram 个数 / reference 中 n-gram 的个数(召回率视角)。例:同上面例句 ROUGE-1 = 5/5 = 1(生成内容完全覆盖参考文本)。
- ROUGE-L:基于最长公共子序列(LCS),不要求匹配单词连续、只要求相对顺序一致,对词序变化鲁棒(子序列:删除若干字符不改变相对顺序,如 “ace” 是 “abcde” 的子序列)。依赖三个指标:精确率
P_LCS = LCS(X,Y)/n、召回率R_LCS = LCS(X,Y)/m(m 参考句长、n 生成句长)、F1 = 2·P·R/(P+R)。 - 代码:
from rouge import Rouge;rouge.get_scores(generated, reference)返回 rouge-1/2/l 的 p、r、f。
7.3.3 PPL(困惑度)
- 用来度量概率分布/概率模型预测样本的好坏程度;给测试集句子赋予较高概率的模型较好。
- 公式:
PPL(S) = exp(-(1/N)·log p(w1,w2,...,wn));1-gram 下简化为exp(-(1/N)·Σ log p(wi))。 - 结论:句子概率越大 → 语言模型越好 → 困惑度越小。
- 企业使用:评估微调前后模型在特定语料上的 PPL(如通用模型 qwen2.5-7B vs 垂直领域微调模型 qwen2.5-7B-SFT,微调后 PPL 应该越小)。
7.4 通用大模型评估任务 / 国内外大模型差异
- 通用大模型评估任务;国内外大模型差异:SuperCLUE 中文大模型测评基准(superclueai.com 榜单)、OpenRouter 实际使用排名(openrouter.ai/rankings)等平台
八、15–20 个高频问题
- 深度学习和传统机器学习的区别? 深度学习以多层人工神经网络为架构、自动提取特征;传统机器学习依赖人工设计特征工程。深度学习需要更多数据与算力、可解释性差。
- 为什么神经网络需要激活函数? 没有激活函数时多层线性变换叠加仍是线性模型;激活函数引入非线性因素,使网络能逼近任意函数、拟合线性不可分问题;BP 要求激活函数可微。
- ReLU 为什么比 Sigmoid 好? ① 无指数运算,计算量小;② x>0 时导数为 1,梯度不衰减,缓解梯度消失,可训练深层网络;③ 输出为 0 形成稀疏性,减少参数相互依存,缓解过拟合。缺点是 x<0 导数恒 0 导致”神经元死亡”。
- 梯度消失的原因是什么? 反向传播用链式法则连乘各层梯度:sigmoid 导数最大 0.25、tanh 导数最大 1 且两侧趋 0,深层连乘使梯度指数级缩小趋 0(sigmoid 约 5 层即消失),浅层参数几乎不更新。解决方案:ReLU、合理初始化(xavier/kaiming)、BN、ResNet 残差连接等。
- Sigmoid 有哪些缺点? ① 饱和区导数≈0 → 梯度消失;② 输出不以 0 为中心(恒正),更新方向单一;③ 指数运算计算量大。一般只用于二分类输出层。
- 梯度爆炸是什么?如何产生? 网络层间梯度大于 1 时连乘导致指数级增长(如 MSE 损失在误差大时梯度大、初始权重过大)。缓解:合理初始化、梯度裁剪、BN、降低学习率。
- 全连接网络的参数数量怎么算? 每层参数 = 输入特征数 × 输出神经元数 + 输出神经元数(每个神经元 w 个数 + 1 个 b)。例 3→3 层为 3×4=12 个。
- Epoch、Batch、Iteration 的区别? Epoch=全部数据完整训练一次;Batch=每次参数更新用的样本数;Iteration=用 1 个 Batch 更新一次参数。50000 样本、batch=256 → 每 epoch 约 196 个 iteration。
- 反向传播(BP)的原理? 利用链式法则从输出层向输入层依次求损失对各参数的偏导(梯度),结合梯度下降更新权重:w = w – lr·grad。”反向传播传播的是梯度”。
- Momentum、AdaGrad、RMSProp、Adam 的区别? Momentum 用梯度的指数加权平均加速收敛、跨鞍点;AdaGrad 按历史梯度平方和自适应降学习率(易过早衰减);RMSProp 用指数加权平均替代平方和,解决过早衰减;Adam = Momentum + RMSProp,同时修正梯度与学习率,最常用。
- 为什么训练后期要减小学习率? 后期学习率过大会导致 loss 振荡、跳过最优点;过小又收敛慢。衰减方式:StepLR 等间隔、MultiStepLR 指定间隔、ExponentialLR 指数衰减(lr=lr·γ^epoch)。
- Dropout 的原理?训练和测试有什么区别? 训练时神经元以概率 p 随机置 0,未置 0 的缩放 1/(1-p)(保持期望不变),等价训练子网络集成、防过拟合;测试时 Dropout 不生效(model.eval() 用全部神经元)。
- Batch Normalization 的作用与训练/推理差异? 对每层输入标准化(均值 0 方差 1)再缩放平移(可学习 γ、β),减少内部协方差偏移、加速收敛、有正则化效果;放在激活函数之前。训练时用当前 batch 统计量并维护全局移动平均,推理时用全局统计量(model.eval())。
- 卷积核、步长、填充的作用?特征图尺寸怎么算? 卷积核提取局部特征(一个卷积核=一个神经元);步长控制滑动步伐(越大特征图越小);填充保持尺寸、保留边缘信息。公式:N = (W-F+2P)/S + 1(向下取整)。
- CNN 相比全连接网络的优势? 局部连接(局部感受野)+ 权值共享 → 参数大大减少、符合图像空间结构;具有平移不变性;自动提取层次化特征(低层边缘→高层物体)。
- 池化的作用?最大池化和平均池化的区别? 降维减少计算量与参数、提高鲁棒性、防过拟合、提取抽象特征;最大池化取窗口最大值(保留显著特征),平均池化取均值(保留整体信息);池化前后通道数不变。
- ResNet 解决什么问题? 通过残差块(跳跃连接)让梯度可直接反向传播到浅层,解决深度网络的梯度消失,可训练 50/152 层极深网络。
- RNN 的原理?为什么难以捕捉长期依赖? RNN 用隐藏状态 h_t=tanh(W_ih·x_t+W_hh·h_(t-1)+b) 循环传递信息,适合序列数据;但随时间步展开很深,梯度连乘导致梯度消失/爆炸,长距离信息丢失,故标准 RNN 难以捕捉长期依赖(资料未涉及 LSTM/GRU 门控细节)。
- 词嵌入(Embedding)相比 one-hot 的好处?nn.Embedding 参数含义? one-hot 高维稀疏、无法表达语义相似性;词嵌入低维稠密、能学习词间语义关系、降低维度。
nn.Embedding(num_embeddings=词数量, embedding_dim=词向量维度)。 - 文本生成为什么是分类问题?预测流程如何? 词表大小 = 类别数,每个时间步预测下一个词即对词表分类;流程:词嵌入 → RNN 更新隐藏状态 → 全连接输出每个词的得分 → softmax 转概率 → 取概率最大的词作为下一时间步输入,迭代生成。
- 语言模型是什么?N-gram 有什么缺陷? 语言模型计算句子序列概率 P(S)(或预测下一个词)。N-gram 依据前 N-1 个词预测,缺陷:参数空间过大与数据稀疏(未出现组合概率为 0)。
- BLEU、ROUGE、PPL 分别是什么? BLEU:机器翻译与参考译文 n-gram 匹配(重精确率),0~1 越大越好;ROUGE:摘要/问答与参考答案匹配(重召回率),ROUGE-L 基于最长公共子序列;PPL:困惑度 = exp(-(1/N)Σlog p(w)),越小越好,用于评估语言模型在语料上的概率拟合。
- 什么是扩展法则(Scaling Law)与涌现能力? Scaling Law:模型参数/数据规模指数级提升时性能线性上升;涌现能力:大模型具有而小模型不具有的能力(如 GPT-3 的上下文学习 ICL),这也是”大语言模型”区别于小预训练模型的原因。
- PyTorch 中为什么梯度要清零?为什么用 x.data 更新而不是 x = x – lr·grad? 梯度默认累加(x.grad 是历史梯度之和),不清零会叠加错误梯度;
x = x - lr·grad会创建新张量、破坏计算图,需用x.data = x.data - lr·x.grad就地更新原始数据。 - 为什么 nn.CrossEntropyLoss 前不需要手动 softmax? PyTorch 的 CrossEntropyLoss = softmax + 交叉熵损失一体化实现,直接接收网络 logits 与类别索引(int64)即可;若自己加了 softmax 再用它会产生双重 softmax 错误。