前言

本文档系统梳理深度学习全链路核心知识点,基于 PyTorch 框架实现,包含完整概念详解 + 可直接运行的代码实战 + 工业级标准化训练流程,覆盖从张量基础到 ANN/CNN/RNN 三大核心网络,适合深度学习入门、进阶学习与面试复习。


目录

  1. 深度学习简介
  2. PyTorch 环境搭建
  3. PyTorch 核心:张量 Tensor 操作
  4. PyTorch 自动微分机制 Autograd
  5. ANN 人工神经网络
  6. CNN 卷积神经网络
  7. RNN 循环神经网络
  8. 深度学习模型通用训练开发流程
  9. 核心知识点重点总结

1. 深度学习简介

1.1 深度学习的核心定义

深度学习是机器学习的一个分支,是一种以深层神经网络为载体,自动从海量数据中学习特征表示的算法体系。它无需人工手动设计特征,能够端到端地完成复杂任务的学习与推理。

1.2 深度学习的核心特点

  1. 端到端的特征自动学习:无需人工提取特征,模型自动从原始数据中学习从底层到高层的特征表示(比如图像从边缘→纹理→物体→场景的层级特征)
  2. 黑盒特性:当前深度学习模型的内部决策逻辑无法完全可解释,仅能通过输入输出的对应关系验证效果,属于数据驱动的黑盒模型
  3. 核心适用场景:以分类任务为核心,同时覆盖回归、生成、分割、检测等几乎所有 AI 任务
  4. 数据依赖:模型效果高度依赖数据量与数据质量,深层网络需要海量标注数据支撑训练

1.3 深度学习与机器学习的核心区别

对比维度传统机器学习深度学习
特征提取人工手动设计特征模型自动学习特征
数据依赖小样本即可训练依赖海量标注数据
计算需求普通 CPU 即可完成高度依赖 GPU/TPU 算力
可解释性可解释性强黑盒模型,可解释性弱

2. PyTorch 环境搭建

PyTorch 是当前学术界与工业界最主流的深度学习框架,采用动态计算图设计,语法简洁、调试友好,是深度学习入门的首选框架。

2.1 官方稳定版安装(pip 方式)

# CPU版本安装(无NVIDIA显卡首选)
pip install torch torchvision torchaudio

# GPU版本安装(需匹配CUDA版本,以CUDA 12.1为例)
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

2.2 安装验证

安装完成后,执行以下代码验证安装是否成功,同时查看 CUDA 是否可用:

import torch

# 查看PyTorch版本
print(f"PyTorch版本:{torch.__version__}")
# 查看CUDA是否可用
print(f"CUDA是否可用:{torch.cuda.is_available()}")
# 查看CUDA版本
print(f"CUDA版本:{torch.version.cuda}")

3. PyTorch 核心:张量 Tensor 操作

张量(Tensor)是 PyTorch 的底层核心数据结构,深度学习的所有计算都基于张量完成。张量只能存储数字类型数据,可以理解为高维数组:

  • 0 维张量:标量(单个数字)
  • 1 维张量:向量(一维数组)
  • 2 维张量:矩阵(二维数组)
  • 3 维及以上张量:高维数组(如图像、视频、序列数据)

3.1 张量的创建方式

3.1.1 普通创建方式
API功能说明注意事项
torch.tensor(data, dtype)最常用的张量创建方式传入列表 / 数组,dtype 指定数据类型(如torch.float32
torch.Tensor()类构造方式创建张量传入标量时,表示张量的元素个数;传入数值需用[]包裹
torch.ShortTensor()/IntTensor()/FloatTensor()指定数据类型的构造方式后缀对应张量的默认数据类型

代码示例

import torch

# 1. 最常用的tensor创建方式
t1 = torch.tensor([[1,2,3], [4,5,6]], dtype=torch.float32)
print("t1:\n", t1)
print("t1形状:", t1.shape)

# 2. torch.Tensor()构造方式
t2 = torch.Tensor(3)  # 传入标量3,创建长度为3的张量,元素为随机值
print("t2:\n", t2)
t3 = torch.Tensor([3])  # 传入[3],创建值为3的张量
print("t3:\n", t3)
3.1.2 线性序列创建
API功能说明核心注意事项
torch.arange(start, end, step)创建等差序列张量区间左闭右开,step 为步长
torch.linspace(start, end, steps)创建等间隔序列张量区间左右均为闭区间,steps 为元素个数

代码示例

# 1. arange创建
t4 = torch.arange(0, 10, 2)  # 0,2,4,6,8(不包含10)
print("t4:", t4)

# 2. linspace创建
t5 = torch.linspace(0, 10, 5)  # 0,2.5,5,7.5,10(包含10,共5个元素)
print("t5:", t5)
3.1.3 随机张量创建
API功能说明核心特性
torch.rand(size)生成 [0,1) 区间的均匀分布随机张量所有值均大于等于 0,小于 1
torch.randn(size)生成标准正态分布随机张量均值为 0,方差为 1
torch.randint(low, high, size)生成 [low, high) 区间的整数随机张量区间左闭右开,size 指定张量形状

随机数种子控制:固定随机数种子,保证每次运行生成的随机数完全一致,可复现实验结果

# 获取当前随机数种子
print("当前随机数种子:", torch.initial_seed())
# 设置固定随机数种子
torch.manual_seed(42)

# 随机张量创建示例
t6 = torch.rand(2,3)  # 2行3列,[0,1)均匀分布
print("t6:\n", t6)
t7 = torch.randn(2,3)  # 2行3列,标准正态分布
print("t7:\n", t7)
t8 = torch.randint(0, 10, (2,3))  # 2行3列,0-9的整数
print("t8:\n", t8)
3.1.4 指定值张量创建
API功能说明
torch.zeros(size) / torch.zeros_like(tensor)创建全 0 张量;创建与输入张量形状一致的全 0 张量
torch.ones(size) / torch.ones_like(tensor)创建全 1 张量;创建与输入张量形状一致的全 1 张量
torch.full(size, fill_value) / torch.full_like(tensor, fill_value)创建填充指定值的张量

代码示例

t9 = torch.zeros(2,3)  # 2行3列全0张量
print("t9:\n", t9)
t10 = torch.ones_like(t9)  # 和t9形状一致的全1张量
print("t10:\n", t10)
t11 = torch.full((2,3), fill_value=5)  # 2行3列,所有元素为5
print("t11:\n", t11)

3.2 张量元素类型修改

共有 3 种常用的张量类型修改方式,适用不同场景:

  1. 创建时指定类型torch.tensor(data, dtype=xxx),dtype 传入小写类型(如torch.float32torch.int64
  2. type () 方法修改张量对象.type(dtype),dtype 可传入类型名(如torch.float32)或构造类(如torch.FloatTensor
  3. 快捷方法修改张量对象.half()/float()/double()/short()/int()/long(),直接转为对应精度类型

代码示例

t = torch.tensor([1,2,3])
print("原始类型:", t.dtype)

# 1. 转为float32类型
t_float = t.float()
print("float32类型:", t_float.dtype)

# 2. 转为int64类型
t_long = t.type(torch.long)
print("int64类型:", t_long.dtype)

# 3. 转为半精度float16
t_half = t.half()
print("float16类型:", t_half.dtype)

3.3 张量类型转换

3.3.1 张量 ↔ Numpy 数组
转换方式代码内存共享说明
张量 → Numpy张量对象.numpy()共享内存,修改一个另一个同步变化
张量 → Numpy(不共享)张量对象.numpy().copy()不共享内存,相互独立
Numpy → 张量torch.from_numpy(numpy数组)共享内存,修改一个另一个同步变化
Numpy → 张量(不共享)torch.tensor(numpy数组)不共享内存,相互独立

代码示例

import numpy as np

# 张量转Numpy
t = torch.tensor([1,2,3])
np_arr = t.numpy()
print("张量转Numpy:", np_arr)

# Numpy转张量
np_arr2 = np.array([4,5,6])
t2 = torch.from_numpy(np_arr2)
print("Numpy转张量:", t2)
3.3.2 张量 ↔ 标量
转换方式代码注意事项
标量 → 张量torch.tensor(标量值)直接创建 0 维张量
张量 → 标量张量对象.item()仅支持只有 1 个元素的张量,否则会报错

代码示例

# 标量转张量
scalar = 10
t = torch.tensor(scalar)
print("标量转张量:", t)

# 张量转标量
t2 = torch.tensor(20)
scalar2 = t2.item()
print("张量转标量:", scalar2)

3.4 张量数值计算

3.4.1 基础四则运算
运算非原地操作(不修改原张量)原地操作(修改原张量)推荐符号写法
加法add()add_()+
减法sub()sub_()-
乘法mul()mul_()*
除法div()div_()/
取反neg()neg_()-

核心规则:PyTorch 中,方法名末尾带_的均为原地操作,会直接修改原张量;不带_的会返回新张量,原张量不受影响。

代码示例

a = torch.tensor([1,2,3])
b = torch.tensor([4,5,6])

# 推荐符号写法
print("加法:", a + b)
print("乘法:", a * b)

# 非原地操作
c = a.add(b)
print("非原地加法结果:", c)
print("原张量a不变:", a)

# 原地操作
a.add_(b)
print("原地加法后a被修改:", a)
3.4.2 点乘(对应元素相乘)
  • 规则:两个张量形状必须完全一致,对应位置的元素相乘
  • 实现方式:张量1.mul(张量2)张量1 * 张量2

代码示例

a = torch.tensor([[1,2],[3,4]])
b = torch.tensor([[5,6],[7,8]])
print("点乘结果:\n", a * b)
3.4.3 矩阵乘法
  • 规则:前一个张量的列数必须等于后一个张量的行数
  • 实现方式:torch.matmul(张量1, 张量2)张量1 @ 张量2(推荐)

代码示例

a = torch.tensor([[1,2,3], [4,5,6]])  # 形状(2,3)
b = torch.tensor([[1,2], [3,4], [5,6]])  # 形状(3,2)
print("矩阵乘法结果:\n", a @ b)  # 输出形状(2,2)

3.5 张量常用运算函数

函数功能说明核心参数
min()/max()求张量的最小值 / 最大值dim 指定计算维度
log()/exp()/pow()/sqrt()对数、指数、幂、开方运算逐元素计算
sum(dim)/mean(dim)求和 / 求均值dim=-1:以最内层维度为最小计算单元;不指定 dim 则对所有元素计算,返回标量

代码示例

t = torch.tensor([[1,2,3], [4,5,6]])

# 对所有元素求和
print("所有元素求和:", t.sum())

# 按行求和(dim=1,最内层维度)
print("按行求和:", t.sum(dim=-1))

# 按列求均值
print("按列求均值:", t.mean(dim=0))

3.6 张量索引操作

3.6.1 基础行列索引
索引写法功能说明
张量对象[i]取第 i 行
张量对象[:, j]取第 j 列
3.6.2 范围索引
  • 语法:张量对象[行起始:行结束:步长, 列起始:列结束:步长]
  • 核心规则:区间左闭右开,步长默认为 1,:表示取该维度的所有元素

代码示例

t = torch.tensor([[1,2,3,4],
                   [5,6,7,8],
                   [9,10,11,12]])

# 取第一行
print("第一行:", t[0])

# 取第一列
print("第一列:", t[:, 0])

# 取前2行,第2-4列
print("范围索引:\n", t[0:2, 1:4])

3.7 张量形状调整

所有形状调整操作必须满足:调整前后张量的元素总个数不变

方法功能说明核心注意事项
reshape(shape)通用形状调整,支持升维、降维、改形状-1表示让 PyTorch 自动计算该维度的大小,最多只能出现 1 次
unsqueeze(dim)升维,在指定 dim 位置增加一个形状为 1 的维度常用于匹配批次维度、通道维度
squeeze(dim)降维,删除形状为 1 的维度不指定 dim 则删除所有形状为 1 的维度;指定 dim 仅当该维度形状为 1 时才会删除
transpose(dim1, dim2)交换两个维度的位置一次只能交换两个维度
permute(dims)重排所有维度的顺序一次可以交换任意多个维度
view(shape)形状调整,功能与 reshape 类似仅支持逻辑顺序与物理存储顺序一致的张量,否则会报错

代码示例

t = torch.tensor([[1,2,3,4,5,6]])
print("原始形状:", t.shape)  # (1,6)

# 1. reshape调整形状
t_reshape = t.reshape(2,3)
print("reshape后形状:", t_reshape.shape)  # (2,3)
t_reshape2 = t.reshape(-1, 2)  # -1自动计算为3
print("reshape带-1形状:", t_reshape2.shape)  # (3,2)

# 2. 升维unsqueeze
t_unsqueeze = t.unsqueeze(dim=0)
print("升维后形状:", t_unsqueeze.shape)  # (1,1,6)

# 3. 降维squeeze
t_squeeze = t.squeeze()
print("降维后形状:", t_squeeze.shape)  # (6,)

# 4. 维度交换transpose
t2 = torch.randn(2,3,4)  # (batch, channel, feature)
t_transpose = t2.transpose(1,2)
print("transpose后形状:", t_transpose.shape)  # (2,4,3)

# 5. 维度重排permute
t_permute = t2.permute(2,0,1)
print("permute后形状:", t_permute.shape)  # (4,2,3)

3.8 张量拼接操作

方法功能说明核心规则
torch.cat(tensors, dim) / concat张量拼接1. 除了拼接的 dim 维度,其他维度形状必须完全一致;2. 拼接后不会升维,维度数不变
torch.stack(tensors, dim)张量堆叠1. 所有参与拼接的张量形状必须完全一致;2. 拼接后会升维,维度数 + 1

代码示例

a = torch.tensor([[1,2], [3,4]])
b = torch.tensor([[5,6], [7,8]])

# 1. cat按行拼接(dim=0)
cat_row = torch.cat([a,b], dim=0)
print("按行cat结果:\n", cat_row)
print("cat后形状:", cat_row.shape)  # (4,2),维度数不变

# 2. cat按列拼接(dim=1)
cat_col = torch.cat([a,b], dim=1)
print("按列cat结果:\n", cat_col)
print("cat后形状:", cat_col.shape)  # (2,4),维度数不变

# 3. stack堆叠
stack_result = torch.stack([a,b], dim=0)
print("stack结果:\n", stack_result)
print("stack后形状:", stack_result.shape)  # (2,2,2),升维

4. PyTorch 自动微分机制 Autograd

自动微分是 PyTorch 的核心灵魂,是神经网络反向传播的底层基础,能够自动计算损失函数对模型参数的梯度,无需手动推导复杂的求导公式,大幅降低深度学习的开发门槛。

4.1 自动微分的核心概念

4.1.1 前向传播与反向传播
  • 前向传播:输入数据经过神经网络的层层计算,得到预测结果,并根据预测结果与真实标签计算损失值的过程。核心是构建计算图、计算预测值与损失值。
  • 反向传播:以损失值为起点,根据链式求导法则,反向计算损失函数对模型中每个可学习参数的梯度,再通过优化器更新参数,让损失值不断减小的过程。核心是梯度计算与参数更新。
4.1.2 计算图

计算图是用来描述运算过程的有向无环图(DAG),由节点和边组成:

  • 节点:代表张量或运算操作
  • 边:代表张量的流向与运算的依赖关系

计算图分为两种:

  • 静态计算图:先定义完整计算图,再执行计算,代表框架为 TensorFlow 1.x
  • 动态计算图:代码执行过程中动态构建计算图,代表框架为 PyTorch,调试更友好、语法更灵活,支持 Python 原生控制流。

4.2 自动微分核心属性与 API

4.2.1 核心属性
属性功能说明核心规则
requires_grad布尔值,标记张量是否需要计算梯度1. 模型可学习参数(权重 w、偏置 b)默认requires_grad=True;2. 输入数据、标签默认requires_grad=False;3. 运算中只要有一个张量requires_grad=True,输出张量自动为 True
grad存储张量的梯度值反向传播后,损失函数对该张量的梯度会保存在这里,仅叶子张量的梯度会被永久保留
grad_fn记录张量的生成函数是反向传播计算梯度的依据,用户手动创建的叶子张量grad_fn=None,运算得到的张量grad_fn为对应的运算函数
is_leaf标记是否为叶子张量叶子张量是用户手动创建、不依赖其他张量的张量,模型可学习参数均为叶子张量;仅叶子张量的梯度会被保留,非叶子张量梯度反向传播后会被自动释放
4.2.2 核心 API
API功能说明适用场景
tensor.backward(gradient=None, retain_graph=None)触发反向传播,自动计算梯度模型训练的反向传播步骤,必须由标量张量调用
torch.no_grad()上下文管理器,包裹的代码块关闭梯度计算模型推理 / 评估阶段,节省显存与算力,避免不必要的梯度计算
tensor.detach()分离张量,返回与原张量共享数据但requires_grad=False的新张量将张量脱离计算图,用于冻结模型参数、截断梯度传播
tensor.retain_grad()为非叶子张量保留梯度调试时查看中间层的梯度,默认非叶子张量梯度会被释放

4.3 自动微分使用核心注意事项

  1. 反向传播触发条件backward()只能由标量张量调用;若为非标量张量,需传入gradient参数,形状与调用张量完全一致。
  2. 计算图释放规则:默认情况下,一次backward()执行完成后,计算图会被自动释放;若需要多次反向传播,需设置retain_graph=True
  3. 梯度累加特性:多次执行backward()后,梯度会累加而非覆盖,因此每次训练迭代前必须手动执行optimizer.zero_grad()清零梯度,避免梯度污染。
  4. 推理阶段必须关闭梯度:模型评估 / 预测时,无需计算梯度,必须使用torch.no_grad()关闭梯度计算,可大幅节省显存、提升推理速度。

4.4 自动微分完整代码实战

4.4.1 基础求导示例

求函数 y=x2+2x+1 在 x=3 处的导数,手动推导导数公式为 y′=2x+2,x=3 时导数为 8。

import torch

# 1. 创建叶子张量x,requires_grad=True表示需要计算梯度
x = torch.tensor(3.0, requires_grad=True)

# 2. 前向传播:定义函数y
y = x ** 2 + 2 * x + 1

# 3. 反向传播:自动计算梯度
y.backward()

# 4. 输出x的梯度值
print(f"x的梯度值为:{x.grad}")  # 输出:x的梯度值为:8.0
4.4.2 非标量张量的反向传播
import torch

# 创建叶子张量x
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)

# 前向传播:y = x * 2(y为非标量)
y = x * 2

# 反向传播:传入gradient=torch.ones_like(y)
y.backward(gradient=torch.ones_like(y))

# 输出x的梯度
print(f"x的梯度值为:{x.grad}")  # 输出:x的梯度值为:tensor([2., 2., 2.])
4.4.3 梯度清零与多次反向传播
import torch

# 创建叶子张量x
x = torch.tensor(3.0, requires_grad=True)

# 第一次反向传播
y1 = x ** 2
y1.backward()
print(f"第一次梯度:{x.grad}")  # 输出:6.0

# 梯度清零(必须操作!否则梯度会累加)
x.grad.zero_()

# 第二次反向传播
y2 = x * 3
y2.backward()
print(f"第二次梯度:{x.grad}")  # 输出:3.0
4.4.4 推理阶段关闭梯度
import torch

model = torch.nn.Linear(10, 2)
x = torch.randn(5, 10)

# 训练模式:开启梯度计算
model.train()
y_train = model(x)
print(f"训练模式输出requires_grad:{y_train.requires_grad}")  # True

# 推理模式:关闭梯度计算
model.eval()
with torch.no_grad():
    y_eval = model(x)
print(f"推理模式输出requires_grad:{y_eval.requires_grad}")  # False

5. ANN 人工神经网络

人工神经网络(Artificial Neural Network,ANN)是模拟人脑神经元结构的数学模型,是深度学习最基础的网络结构,也是所有复杂网络的核心基础。

5.1 神经元与网络结构

5.1.1 单个神经元的计算流程

单个神经元是神经网络的最小计算单元,计算分为两步:

  1. 线性求和:将输入特征与权重相乘,加上偏置项,得到线性组合z=w1​x1​+w2​x2​+...+wn​xn​+b=WX+b
  2. 激活函数:将线性组合输入激活函数,引入非线性关系,得到神经元的输出a=f(z)
5.1.2 神经网络的整体结构

神经网络由三层核心结构组成:

  1. 输入层:接收原始特征数据,神经元个数等于特征的维度
  2. 隐藏层:负责特征的学习与提取,层数和每层的神经元个数可自定义,网络的深度由隐藏层的层数决定
  3. 输出层:输出模型的预测结果,神经元个数等于任务的类别数(分类任务)或 1(回归任务)

5.2 激活函数详解

激活函数的核心作用是在神经网络中引入非线性关系。如果没有激活函数,无论网络有多少层,都只能等价于一个线性变换,无法处理复杂的非线性问题。

5.2.1 常用激活函数对比
激活函数公式输出区间核心特点适用场景注意事项
Sigmoidf(x)=1+e−x1​(0,1)可输出概率值,同时考虑正负样本二分类输出层;浅层隐藏层导数区间(0,0.25),深层网络极易出现梯度消失,隐藏层使用时层数≤4
Tanhf(x)=ex+e−xex−e−x​(−1,1)数据中心化,梯度消失问题轻于 Sigmoid浅层隐藏层导数区间(0,1),隐藏层使用时层数≤10
ReLU(优先推荐)f(x)=max(0,x)[0,+∞)计算简单、速度快,有效缓解梯度消失所有隐藏层首选只考虑正样本,可能出现 “神经元死亡”(梯度永久为 0)
Softmaxf(xi​)=∑j=1n​exj​exi​​(0,1)所有输出的概率和为 1多分类任务的输出层仅用于多分类输出层,不可用于隐藏层
5.2.2 激活函数使用总结
  • 隐藏层:优先使用 ReLU;浅层网络可使用 Tanh(层数≤10)或 Sigmoid(层数≤4)
  • 输出层:二分类任务可使用 Sigmoid 或 Softmax;多分类任务必须使用 Softmax

5.3 参数初始化策略

参数初始化直接影响模型的训练速度与最终效果,不当的初始化会导致梯度消失 / 爆炸,模型无法收敛。

5.3.1 偏置 b 初始化

推荐使用全 0 初始化,PyTorch 的nn.Linear层默认偏置为全 0 初始化。

5.3.2 权重 w 初始化
初始化方法适用场景
Kaiming 初始化(优先推荐)ReLU 系列激活函数;深层神经网络
Xavier 初始化Sigmoid/Tanh 激活函数;浅层神经网络(≤10 层)

注意:PyTorch 的nn.Linear层内部会自动执行默认初始化,若需自定义可手动覆盖。

5.4 损失函数详解

损失函数用于衡量模型预测值与真实标签的差距,是模型优化的目标,需根据任务类型选择对应的损失函数。

任务类型损失函数适用场景核心注意事项
多分类CrossEntropyLoss(唯一选择)3 类及以上的分类任务内部自带 Softmax 激活函数,输出层绝对不能重复调用 Softmax,否则会导致梯度异常
二分类BCELoss二分类任务输出层必须先通过 Sigmoid 将输出转为概率值,再传入损失函数
二分类CrossEntropyLoss二分类任务可直接用于二分类,无需 Sigmoid,输出层神经元个数为 2
回归L1Loss(MAE)回归任务,对异常值鲁棒梯度恒定,训练后期收敛不稳定
回归MSELoss(L2)回归任务,数据无大量异常值梯度稳定,对异常值极度敏感
回归SmoothL1Loss(优先推荐)所有回归任务综合 L1 和 L2 的优点,对异常值鲁棒,梯度稳定

5.5 优化器与学习率衰减

5.5.1 常用优化器对比

优化器的作用是根据梯度更新模型的可学习参数,让损失值不断减小。

优化器优化对象核心特点推荐优先级
Adam梯度值 + 学习率综合 Momentum 和 RMSProp 的优点,自适应学习率,收敛速度快,稳定性强最高,绝大多数任务首选
Momentum梯度值引入动量,缓解 SGD 的震荡问题,加速收敛中等,简单任务可使用
RMSProp学习率改进 AdaGrad,缓解学习率过早下降的问题,适合稀疏数据中等,文本 / 稀疏数据可使用
AdaGrad学习率自适应学习率,适合稀疏数据,越往后学习率越小低,仅用于特定稀疏场景
SGD梯度值随机梯度下降,无自适应能力,需要精细调参低,仅用于简单任务或学术研究
5.5.2 手动学习率衰减策略

学习率衰减的作用是训练后期降低学习率,让模型更好地收敛到最优解。

表格

衰减策略API核心说明
等间隔衰减torch.optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5)每隔step_size个 epoch,学习率乘以gamma
指定间隔衰减torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[50,125,160], gamma=0.5)milestones指定的 epoch 节点,学习率乘以gamma
指数衰减torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95)每轮学习率更新公式:lr=lr×gammaepoch

5.6 正则化方法(缓解过拟合)

过拟合是指模型在训练集上效果极好,但在测试集 / 新数据上效果极差,泛化能力弱。正则化是缓解过拟合的核心手段。

5.6.1 Dropout 随机失活
  • 核心原理:训练过程中,随机让部分神经元以概率 p 失活(输出置 0),未失活的神经元输出会放大1/(1−p)倍,避免模型过度依赖部分神经元,提升泛化能力。
  • 使用规则
    1. Dropout 层必须加在激活函数的后面
    2. 训练时必须执行model.train(),开启 Dropout
    3. 评估 / 推理时必须执行model.eval(),关闭 Dropout
    4. 失活概率 p 通常设置为 0.2-0.5
5.6.2 批量归一化 BN(BatchNorm)
  • 核心原理:对每个批次的数据单独做标准化处理,让数据分布稳定,加速模型训练,缓解内部协变量偏移问题,同时有轻微的正则化效果。
  • 使用规则
    1. BN 层加在线性层 / 卷积层之后,激活函数之前
    2. 主要用于计算机视觉任务,训练时model.train(),推理时model.eval()

5.7 ANN 网络搭建与完整训练代码实战

任务说明

构建一个 ANN 人工神经网络,解决二分类任务:输入特征维度为 10,2 层隐藏层,输出二分类概率,包含完整的训练、评估、模型保存流程。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# ====================== 1. 准备数据 ======================
# 生成模拟数据:1000个样本,10个特征,二分类标签
X = torch.randn(1000, 10)  # 特征数据,形状(1000,10)
y = torch.randint(0, 2, (1000, 1)).float()  # 标签,形状(1000,1),值为0或1

# 封装为Dataset和DataLoader,实现批次加载与打乱
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

# ====================== 2. 定义ANN网络结构 ======================
class ANN(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(ANN, self).__init__()
        # 定义网络层
        self.fc1 = nn.Linear(input_dim, hidden_dim)  # 输入层→隐藏层1
        self.bn1 = nn.BatchNorm1d(hidden_dim)  # 批量归一化
        self.relu1 = nn.ReLU()  # 激活函数
        self.dropout1 = nn.Dropout(0.3)  # Dropout正则化
        
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)  # 隐藏层1→隐藏层2
        self.bn2 = nn.BatchNorm1d(hidden_dim)
        self.relu2 = nn.ReLU()
        
        self.fc3 = nn.Linear(hidden_dim, output_dim)  # 隐藏层2→输出层
        self.sigmoid = nn.Sigmoid()  # 二分类输出层用Sigmoid,输出概率

    def forward(self, x):
        # 前向传播流程
        x = self.fc1(x)
        x = self.bn1(x)
        x = self.relu1(x)
        x = self.dropout1(x)
        
        x = self.fc2(x)
        x = self.bn2(x)
        x = self.relu2(x)
        
        x = self.fc3(x)
        x = self.sigmoid(x)
        return x

# 实例化模型
model = ANN(input_dim=10, hidden_dim=20, output_dim=1)

# ====================== 3. 定义损失函数、优化器、学习率衰减 ======================
criterion = nn.BCELoss()  # 二分类损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam优化器
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.5)  # 每20轮学习率减半

# ====================== 4. 模型训练 ======================
epochs = 50
model.train()  # 开启训练模式(Dropout、BN生效)

for epoch in range(epochs):
    total_loss = 0.0
    # 内层循环:遍历每个批次
    for batch_X, batch_y in dataloader:
        # 4.1 前向传播:得到预测值
        predictions = model(batch_X)
        # 4.2 计算损失值
        loss = criterion(predictions, batch_y)
        
        # 4.3 反向传播(固定三步,不可调换顺序)
        optimizer.zero_grad()  # 1. 梯度清零
        loss.backward()        # 2. 反向传播计算梯度
        optimizer.step()       # 3. 更新模型参数
        
        total_loss += loss.item()
    
    # 每轮结束更新学习率
    scheduler.step()
    
    # 打印训练日志
    avg_loss = total_loss / len(dataloader)
    current_lr = optimizer.param_groups[0]['lr']
    print(f"Epoch [{epoch+1}/{epochs}], 平均损失: {avg_loss:.4f}, 当前学习率: {current_lr:.6f}")

# ====================== 5. 模型评估 ======================
model.eval()  # 开启评估模式(Dropout、BN关闭)
with torch.no_grad():  # 关闭梯度计算,节省显存
    # 生成模拟测试数据
    test_X = torch.randn(100, 10)
    test_y = torch.randint(0, 2, (100, 1)).float()
    
    # 模型预测
    test_predictions = model(test_X)
    # 将概率转为类别:>0.5为1,否则为0
    test_classes = (test_predictions > 0.5).float()
    
    # 计算准确率
    accuracy = (test_classes == test_y).sum().item() / len(test_y)
    print(f"\n测试集准确率: {accuracy:.2%}")
    print(f"前10个测试样本预测类别: {test_classes[:10].squeeze().numpy()}")

# ====================== 6. 模型保存 ======================
torch.save(model.state_dict(), "ann_binary_classification.pth")
print("\n模型已保存为 ann_binary_classification.pth")

6. CNN 卷积神经网络

卷积神经网络(Convolutional Neural Network,CNN)是专门为处理图像、视频等网格结构数据设计的神经网络,核心是通过卷积层自动提取图像的层级特征,是计算机视觉任务的基础模型。

6.1 CNN 的核心原理

CNN 之所以适合处理图像,核心是它具备两个关键特性:

  1. 局部感受野:卷积核只关注图像的局部区域,而非整张图,符合人类视觉的局部感知特性
  2. 参数共享:同一个卷积核在整张图像上滑动共享参数,大幅减少模型的参数量,避免过拟合

6.2 CNN 的整体结构

CNN 由三层核心结构组成:

  1. 输入层:接收图像张量,标准格式为[N, C, H, W]
    • N:批次大小(一次输入的图片数量)
    • C:通道数(彩色图 = 3,灰度图 = 1)
    • H:图像高度
    • W:图像宽度
  2. 隐藏层
    • 卷积层:核心层,从图像中提取层级特征(边缘→纹理→物体→场景)
    • 激活函数:通常使用 ReLU,引入非线性
    • 池化层:对特征图进行降维,减少参数量,提升感受野,缓解过拟合
  3. 输出层:将三维特征图展平为二维向量,送入全连接层(线性层),输出最终的分类 / 检测结果

6.3 卷积层详解

6.3.1 卷积层核心参数
参数功能说明常用取值
in_channels输入特征图的通道数彩色图像输入为 3,后续层等于上一层的 out_channels
out_channels输出特征图的通道数,等于卷积核的个数16、32、64、128 等,通常逐层翻倍
kernel_size卷积核的大小3(最常用)、5、7
stride卷积核在图像上滑动的步长1(不改变尺寸)、2(尺寸减半)
padding图像四周的填充圈数,填充值默认为 00、1、2,通常设置为kernel_size//2,让卷积后尺寸不变
6.3.2 特征图尺寸计算公式

卷积 / 池化后,特征图的尺寸计算公式为:

Hout​=⌊strideHin​+2×padding−kernel_size​⌋+1Wout​=⌊strideWin​+2×padding−kernel_size​⌋+1

示例:输入图像尺寸 32×32,卷积核 3×3,stride=1,padding=1,输出尺寸为:

Hout​=⌊132+2×1−3​⌋+1=32

即卷积后尺寸不变。

6.3.3 卷积层 API
import torch.nn as nn

# 定义卷积层:输入通道3,输出通道16,卷积核3×3,步长1,填充1
conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)

6.4 池化层详解

池化层的核心作用是特征降维,在保留关键特征的前提下,减少特征图的尺寸和参数量,同时扩大感受野。

6.4.1 常用池化方式
池化方式核心原理特点推荐优先级
最大池化(MaxPooling)取池化窗口内的最大值作为输出保留图像的显著特征,边缘、纹理等关键信息最高,绝大多数场景首选
平均池化(AvgPooling)取池化窗口内的平均值作为输出保留图像的整体特征,平滑特征图低,仅用于特定场景
6.4.2 池化层 API
import torch.nn as nn

# 最常用的最大池化:窗口2×2,步长2,特征图尺寸直接减半
max_pool_layer = nn.MaxPool2d(kernel_size=2, stride=2)

6.5 卷积层与池化层的核心区别

对比维度卷积层池化层
核心功能提取图像的层级特征,可同步实现降维仅对特征图进行降维,不提取特征
可学习参数卷积核内的权重 w 和偏置 b,是可学习参数无任何可学习参数,仅做固定的最大值 / 平均值计算
计算方式卷积核与图像局部区域做加权求和取窗口内的最大值 / 平均值

6.6 CNN 网络搭建与完整图像分类代码实战

任务说明

构建一个 CNN 卷积神经网络,处理 3 通道彩色图像(输入尺寸 32×32),完成 10 分类任务,包含完整的训练、评估、模型保存流程。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# ====================== 1. 准备数据 ======================
# 生成模拟图像数据:1000张3通道32×32的彩色图像,10分类标签
X = torch.randn(1000, 3, 32, 32)  # 形状[N, C, H, W]
y = torch.randint(0, 10, (1000,))  # 标签,0-9共10个类别

# 封装为Dataset和DataLoader
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

# ====================== 2. 定义CNN网络结构 ======================
class CNN(nn.Module):
    def __init__(self, num_classes=10):
        super(CNN, self).__init__()
        # 第一组:卷积+BN+激活+池化
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
        self.bn1 = nn.BatchNorm2d(16)  # 批量归一化
        self.relu1 = nn.ReLU()
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)  # 尺寸减半:32→16
        
        # 第二组:卷积+BN+激活+池化
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1)
        self.bn2 = nn.BatchNorm2d(32)
        self.relu2 = nn.ReLU()
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)  # 尺寸减半:16→8
        
        # 第三组:卷积+BN+激活+池化
        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)
        self.bn3 = nn.BatchNorm2d(64)
        self.relu3 = nn.ReLU()
        self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)  # 尺寸减半:8→4
        
        # 全连接层:分类输出
        self.fc = nn.Linear(64 * 4 * 4, num_classes)

    def forward(self, x):
        # 第一组前向传播
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu1(x)
        x = self.pool1(x)
        
        # 第二组前向传播
        x = self.conv2(x)
        x = self.bn2(x)
        x = self.relu2(x)
        x = self.pool2(x)
        
        # 第三组前向传播
        x = self.conv3(x)
        x = self.bn3(x)
        x = self.relu3(x)
        x = self.pool3(x)
        
        # 展平:[N, 64, 4, 4] → [N, 64*4*4]
        x = x.flatten(start_dim=1)
        
        # 全连接层输出分类结果
        x = self.fc(x)
        return x

# 实例化模型
model = CNN(num_classes=10)

# ====================== 3. 定义损失函数、优化器 ======================
criterion = nn.CrossEntropyLoss()  # 多分类损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)

# ====================== 4. 模型训练 ======================
epochs = 30
model.train()

for epoch in range(epochs):
    total_loss = 0.0
    for batch_X, batch_y in dataloader:
        # 前向传播
        predictions = model(batch_X)
        loss = criterion(predictions, batch_y)
        
        # 反向传播固定三步
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        total_loss += loss.item()
    
    # 打印训练日志
    avg_loss = total_loss / len(dataloader)
    print(f"Epoch [{epoch+1}/{epochs}], 平均损失: {avg_loss:.4f}")

# ====================== 5. 模型评估 ======================
model.eval()
with torch.no_grad():
    # 生成模拟测试数据
    test_X = torch.randn(100, 3, 32, 32)
    test_y = torch.randint(0, 10, (100,))
    
    # 模型预测
    test_predictions = model(test_X)
    test_classes = torch.argmax(test_predictions, dim=1)  # 取概率最大的类别
    
    # 计算准确率
    accuracy = (test_classes == test_y).sum().item() / len(test_y)
    print(f"\n测试集准确率: {accuracy:.2%}")
    print(f"前10个测试样本预测类别: {test_classes[:10].numpy()}")

# ====================== 6. 模型保存 ======================
torch.save(model.state_dict(), "cnn_image_classification.pth")
print("\n模型已保存为 cnn_image_classification.pth")

7. RNN 循环神经网络

循环神经网络(Recurrent Neural Network,RNN)是专门为处理序列数据设计的神经网络,核心是通过循环层保留序列的上下文信息,是自然语言处理、时间序列预测任务的基础模型。

7.1 RNN 的核心原理

序列数据是指数据之间存在先后顺序依赖关系的数据,比如文本、语音、股票价格、传感器数据等。RNN 的核心特性是:

  • 隐藏状态传递:每个时间步的隐藏状态会传递到下一个时间步,让模型能够记住之前的上下文信息
  • 参数共享:所有时间步共享同一套参数,大幅减少参数量,适配任意长度的序列数据

7.2 序列数据预处理:词嵌入层 Embedding

文本等非数字序列数据无法直接输入神经网络,需要先通过词嵌入层转为低维稠密的词向量。

7.2.1 文本数据处理流程
  1. 分词:将文本句子拆分为单个词语 / 字
  2. 构建词汇表:对所有词语去重,给每个词语分配唯一的数字索引
  3. 词嵌入:根据词语的索引,将其转为固定维度的低维稠密向量(替代 one-hot 的高维稀疏表示)
7.2.2 词嵌入层 API
import torch.nn as nn

# 定义词嵌入层:词汇表大小10000,词向量维度128
embedding_layer = nn.Embedding(num_embeddings=10000, embedding_dim=128)

7.3 循环层详解

7.3.1 循环层核心计算流程

每个时间步的计算分为两步:

  1. 输入:上一个时间步的隐藏状态 + 当前时间步的输入特征
  2. 输出:更新后的当前时间步隐藏状态 + 当前时间步的预测结果

隐藏状态是 RNN 的核心,它存储了序列从开头到当前时间步的所有上下文信息,实现了 “记忆” 能力。

7.3.2 循环层核心参数
参数功能说明
input_size输入特征的维度(词向量的维度)
hidden_size隐藏状态的维度
num_layers循环层的堆叠层数
batch_first若设置为 True,输入 / 输出的形状为[batch_size, seq_len, feature],更符合常规数据格式,推荐开启
7.3.3 张量形状说明(开启 batch_first=True)
张量形状说明
input[batch_size, seq_len, input_size]输入序列数据
h0[num_layers, batch_size, hidden_size]初始隐藏状态,可省略,默认全 0 初始化
output[batch_size, seq_len, hidden_size]每个时间步的输出结果
hidden[num_layers, batch_size, hidden_size]最后一个时间步的隐藏状态,包含整个序列的上下文信息
7.3.4 循环层 API
import torch.nn as nn

# 定义RNN层:输入维度128,隐藏维度64,层数2,开启batch_first
rnn_layer = nn.RNN(input_size=128, hidden_size=64, num_layers=2, batch_first=True)

7.4 RNN 网络搭建与完整文本分类代码实战

任务说明

构建一个 RNN 循环神经网络,处理文本序列数据(词汇表大小 10000,序列长度 20),完成二分类任务,包含完整的训练、评估、模型保存流程。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# ====================== 1. 准备数据 ======================
# 生成模拟文本数据:1000个样本,每个样本序列长度20,词索引范围0-9999,二分类标签
X = torch.randint(0, 10000, (1000, 20))  # 形状[N, seq_len]
y = torch.randint(0, 2, (1000,))  # 标签,0或1

# 封装为Dataset和DataLoader
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

# ====================== 2. 定义RNN文本分类网络结构 ======================
class RNNTextClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_size, num_layers, num_classes):
        super(RNNTextClassifier, self).__init__()
        # 词嵌入层:词索引→词向量
        self.embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embed_dim)
        # RNN循环层
        self.rnn = nn.RNN(
            input_size=embed_dim,
            hidden_size=hidden_size,
            num_layers=num_layers,
            batch_first=True,
            dropout=0.3  # 循环层Dropout
        )
        # 全连接层:分类输出
        self.fc = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        # 1. 词嵌入:[N, seq_len] → [N, seq_len, embed_dim]
        x = self.embedding(x)
        
        # 2. RNN前向传播
        # output:每个时间步的输出,形状[N, seq_len, hidden_size]
        # hidden:最后一个时间步的隐藏状态,形状[num_layers, N, hidden_size]
        output, hidden = self.rnn(x)
        
        # 3. 取最后一个时间步的输出用于分类:[N, hidden_size]
        last_output = output[:, -1, :]
        
        # 4. 全连接层输出分类结果
        x = self.fc(last_output)
        return x

# 实例化模型
model = RNNTextClassifier(
    vocab_size=10000,
    embed_dim=128,
    hidden_size=64,
    num_layers=2,
    num_classes=2
)

# ====================== 3. 定义损失函数、优化器 ======================
criterion = nn.CrossEntropyLoss()  # 二分类损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)

# ====================== 4. 模型训练 ======================
epochs = 20
model.train()

for epoch in range(epochs):
    total_loss = 0.0
    for batch_X, batch_y in dataloader:
        # 前向传播
        predictions = model(batch_X)
        loss = criterion(predictions, batch_y)
        
        # 反向传播固定三步
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        total_loss += loss.item()
    
    # 打印训练日志
    avg_loss = total_loss / len(dataloader)
    print(f"Epoch [{epoch+1}/{epochs}], 平均损失: {avg_loss:.4f}")

# ====================== 5. 模型评估 ======================
model.eval()
with torch.no_grad():
    # 生成模拟测试数据
    test_X = torch.randint(0, 10000, (100, 20))
    test_y = torch.randint(0, 2, (100,))
    
    # 模型预测
    test_predictions = model(test_X)
    test_classes = torch.argmax(test_predictions, dim=1)
    
    # 计算准确率
    accuracy = (test_classes == test_y).sum().item() / len(test_y)
    print(f"\n测试集准确率: {accuracy:.2%}")
    print(f"前10个测试样本预测类别: {test_classes[:10].numpy()}")

# ====================== 6. 模型保存 ======================
torch.save(model.state_dict(), "rnn_text_classification.pth")
print("\n模型已保存为 rnn_text_classification.pth")

8. 深度学习模型通用训练开发流程

所有深度学习模型的训练都遵循标准化的开发流程,掌握该流程可快速适配所有深度学习任务。

8.1 通用训练流程拆解

  1. 准备数据

    • 数据预处理:归一化、标准化、数据增强、标签编码等
    • 数据封装:Tensor → 自定义DatasetDataLoader(实现批次加载、打乱、多线程读取)
    • 数据集划分:训练集、验证集、测试集
  2. 创建核心实例对象

    • 模型实例:继承nn.Module的网络类实例
    • 损失函数实例:根据任务类型选择对应的损失函数
    • 优化器实例:传入模型的可学习参数,设置学习率
    • 【可选】学习率衰减器实例
  3. 双层循环训练

    • 外层循环:控制训练轮次epoch,遍历整个数据集的次数
    • 内层循环:控制批次batch,遍历DataLoader中的每个批次数据
  4. 单批次训练核心四步

    1. 前向传播:将批次特征数据传入模型,自动调用forward方法,得到预测结果
    2. 计算损失:将预测结果与真实标签传入损失函数,计算损失值
    3. 反向传播固定三步
      • optimizer.zero_grad():梯度清零,避免梯度累加污染
      • loss.backward():触发反向传播,自动计算所有可学习参数的梯度
      • optimizer.step():根据梯度更新模型的可学习参数
    4. 【可选】日志打印、指标计算、模型验证
  5. 模型保存与推理

    • 模型保存:torch.save(model.state_dict(), "model.pth")(推荐保存参数,而非整个模型)
    • 模型加载:model.load_state_dict(torch.load("model.pth"))
    • 推理阶段:必须执行model.eval() + with torch.no_grad(),关闭梯度计算与训练专属层

9. 核心知识点重点总结

9.1 机器学习核心基础

  • 线性回归的核心是梯度下降:wnew​=wold​−lr×grad,核心目标是让损失值逼近最小值,得到最优的 w 和 b 参数组合。

9.2 PyTorch 核心基础

  • 张量 Tensor:深度学习唯一的底层数据结构,只能存储数字,所有计算都基于张量完成。
  • 张量核心操作:创建、类型转换、四则运算、矩阵乘法、索引、形状调整、拼接,是所有模型开发的基础。
  • 自动微分:前向传播计算预测值与损失值,反向传播自动计算梯度,是神经网络训练的核心。

9.3 三大核心网络

  • ANN 人工神经网络:基础全连接网络,适合结构化数据的分类、回归任务。
  • CNN 卷积神经网络:专为图像数据设计,核心是卷积层提取特征,是计算机视觉的基础。
  • RNN 循环神经网络:专为序列数据设计,核心是循环层传递上下文信息,是 NLP、时间序列任务的基础。

9.4 模型训练核心准则

  • 训练时必须执行model.train(),推理 / 评估时必须执行model.eval()
  • 反向传播前必须执行梯度清零,避免梯度累加。
  • 推理阶段必须用torch.no_grad()关闭梯度计算,节省显存。
  • 损失函数、激活函数、优化器必须与任务类型匹配,避免出现梯度异常、模型不收敛的问题。

更多推荐