目录
一、概述与基础认知
1.1 深度学习定义
1.2 核心区别(与机器学习)
1.3 优缺点
1.4 发展历史
1.5 常见算法与模型
二、应用场景
三、核心工具:流行框架与张量
3.1 流行深度学习框架
3.2 张量(Tensor):深度学习的核心数据结构
四、PyTorch框架核心模块
4.1 环境安装
4.2 自动微分模块(反向传播求梯度)
4.3 梯度问题:消失与爆炸
五、人工神经网络(ANN)核心技术
5.1 神经元结构与网络构成
5.2 激活函数(面试常问)
5.3 7大参数初始化方法
5.4 损失函数(面试常问)
5.5 优化器:学习率与参数更新的核心(面试重点)
5.6 正则化:解决过拟合的核心技术
六、综合案例:手机价格分类任务
6.1 任务需求
6.2 实现步骤
6.3 案例关键说明
七、核心知识点总结
7.1 技术选型速查表
7.2 常见问题与解决方案
学习目标
-
理解深度学习定义、与机器学习的核心区别及典型应用场景,建立对深度学习的基础认知。
-
掌握PyTorch框架核心操作,包括张量创建与运算、自动微分原理、模型构建与训练流程。
-
精通人工神经网络(ANN)核心技术,涵盖激活函数、参数初始化、损失函数、优化器及正则化方法的选型与应用。
-
熟悉深度学习常见模型(CNN、RNN、Transformer等)的适用场景,理解批量归一化(BN)、Dropout等关键技术的作用机制。
-
能够独立完成深度学习实战任务,包括数据处理、模型搭建、训练优化及结果评估,解决实际问题。
一、概述与基础认知
1.1 深度学习定义
深度学习是机器学习算法的重要分支,以人工神经网络为核心模型,能够自动提取数据特征,无需人工干预特征工程,实现端到端的学习与预测。
1.2 核心区别(与机器学习)
- 特征提取方式:机器学习需人工设计并提取特征;深度学习通过网络结构自动学习和提取特征。
- 模型复杂度:深度学习模型层级更深、参数更多,可处理更复杂的数据模式。
1.3 优缺点
1.3.1 优点
- 精度高,在计算机视觉、自然语言处理等领域性能优于传统机器学习算法,部分场景超过人类水平。
- 随着计算机硬件(GPU/TPU)的发展,可近似拟合任意非线性函数,解决复杂问题。
- 生态完善,学界和业界支持度高,有大量成熟框架(如PyTorch、TensorFlow)可供调用。
1.3.2 缺点
- “黑箱”特性,模型决策过程难以解释,缺乏可解释性。
- 训练时间长,需要大量计算资源支撑,对硬件要求较高。
- 网络结构复杂,超参数调优难度大,需大量经验积累。
- 对小数据集适应性差,易出现过拟合问题。
1.4 发展历史
- 1943年:提出McCulloch-Pitts神经元模型,为人工神经网络奠定基础。
- 1956年:约翰·麦卡锡、香农等人主持达特茅斯会议,首次提出“人工智能”术语。
- 1960年:多层感知器(输入层-隐藏层-输出层)出现,推动神经网络结构发展。
- 2012年:卷积神经网络(CNN)诞生,在图像识别任务中取得突破性成果,引爆深度学习革命。
- 2017年:Transformer框架提出,革新自然语言处理领域的技术路线。
- 2022年:ChatGPT发布,标志着大模型AIGC时代来临。
- 2023年:大模型技术实现爆发式突破,引发全球人工智能研发浪潮。
- 2024年:AI应用大规模落地,硬件与实际场景深度融合。
- 2025年:开启智能体(Agent)时代,AI自主性与决策能力显著提升。
1.5 常见算法与模型
- ANN(人工神经网络):基础网络结构,适用于简单非线性问题。
- CNN(卷积神经网络):擅长处理网格结构数据,核心应用于计算机视觉领域。
- RNN(循环神经网络):针对序列数据设计,可捕捉时间依赖关系,适用于语音、文本等任务。
- Transformer:基于自注意力机制,是当前大语言模型、多模态模型的核心架构(2017年提出)。
- 生成对抗网络(GAN):通过生成器与判别器的对抗训练生成逼真数据,适用于图像生成、风格迁移等场景。
二、应用场景
- 计算机视觉(CV):图像识别(如人脸识别、物体识别)、图像分割(如医学影像病灶分割)、目标检测(如自动驾驶障碍物检测)。
- 自然语言处理(NLP):聊天机器人(如智能客服)、语音翻译(如实时跨境翻译)、生成式AI(如文本创作、代码生成)。
- 推荐系统:电商商品推荐、视频平台内容推荐、电影/音乐/文章个性化推荐。
- 多模态大模型:融合文本、图像、语音等多种数据类型,实现跨模态理解与生成(如文生图、图生文)。
三、核心工具:流行框架与张量
3.1 流行深度学习框架
- TensorFlow:由谷歌开发,工业界应用广泛,生态成熟,支持分布式训练。
- PyTorch:由Meta(原Facebook)开发,API简洁直观,动态计算图特性适合科研实验,是学术界首选框架。
- PaddlePaddle(飞桨):百度自研框架,对中文场景支持友好,无GPU环境下也能高效运行。
- ONNX(开放神经网络交换格式):跨框架的模型存储格式,可实现不同框架(如PyTorch转TensorFlow)的模型互转,被誉为“万物先转ONNX,ONNX转万物”。
3.2 张量(Tensor):深度学习的核心数据结构
张量是多维数组的抽象概念,是深度学习中数据存储和运算的基本单元。维度划分:0维(标量)、1维(向量)、2维(矩阵)、3维(如文本序列:批次×长度×特征)、4维(如图像数据:批次×通道×高度×宽度,在3维基础上增加时间/批次轴)。
3.2.1 张量创建
基本创建方式
- torch.tensor(data=, dtype=):可同时指定数据和数据类型(如torch.float32、torch.int64),灵活性高。
- torch.Tensor(data=, size=()):既可以传入原始数据,也可直接指定张量形状。
- torch.IntTensor()/FloatTensor():直接通过类型后缀指定张量类型创建空张量或初始化张量。
线性与随机张量
- 线性张量:
torch.arange(start=, end=, step=):生成指定范围的连续整数,左闭右开(end不包含),step为步长。
- torch.linspace(start=, end=, steps=):在指定区间内生成均匀分布的steps个数值,左闭右闭(end包含)。
随机张量:
torch.rand(size=()):生成0到1之间均匀分布的浮点数。
torch.randn(size=()):生成标准正态分布(均值0,方差1)的浮点数。
torch.randint(low=, high=, size=()):生成[low, high)区间内的随机整数。
随机种子:torch.manual_seed(常数)设置随机种子(保证实验可复现);torch.initial_seed()查看当前随机种子。
0/1/指定值张量
- torch.zeros(size=())/torch.ones(size=()):根据指定形状生成全0/全1张量。
- torch.zeros_like(input=tensor)/torch.ones_like(input=tensor):根据输入张量的形状生成全0/全1张量,避免手动匹配形状。
- torch.full(size=(), fill_value=):生成指定形状且所有元素为fill_value的张量。
- torch.full_like(input=tensor, fill_value=):根据输入张量形状生成填充指定值的张量。
3.2.2 类型转换
- 张量转NumPy数组:
tensor.numpy():转换后的数据与原张量共享内存,修改一方会影响另一方。
- tensor.numpy().copy():深拷贝转换,不共享内存,双方独立。
NumPy数组转张量:
torch.from_numpy(data=ndarray):共享内存,适合大数据快速转换。
torch.tensor(data=ndarray):深拷贝转换,不共享内存,数据更安全。
标量与单元素张量互转:
标量转张量:torch.tensor(标量值)(如torch.tensor(5.0))。
单元素张量转标量:tensor.item()(仅适用于包含一个元素的张量)。
3.2.3 数字计算
基础运算
- 运算符:+、-、*、/(元素级运算)。
- 函数形式:torch.add()、torch.sub()、torch.mul()、torch.div(),功能与运算符一致,支持更多参数配置。
- 原位运算:tensor.add_()、sub_()、mul_()、div_(),直接修改原张量数据,不创建新对象,节省内存。
- 负号操作:tensor.neg()(返回新张量)、tensor.neg_()(原位修改)。
矩阵乘法运算
- 运算规则:若张量A形状为(n, m),张量B形状为(m, p),则乘积C形状为(n, p),即“前矩阵列数=后矩阵行数”。
- 实现方式:
PyTorch:@运算符或torch.matmul()(支持高维张量批量矩阵乘法);注意torch.dot()仅支持1维张量的点积。
- NumPy:@、np.matmul()、np.dot()(高维场景下与matmul有差异)。
3.2.4 运算函数
- min/max/mean/sum(dim=):
不指定dim:对张量所有元素计算全局结果(返回单元素张量)。
- 指定dim:沿指定维度计算(dim=0为列方向,dim=1为行方向),返回该维度压缩后的张量。
sqrt():计算每个元素的平方根。
log()/log2()/log10()/log1p():分别计算自然对数、以2为底的对数、以10为底的对数、log(1+x)(避免x接近0时的计算误差)。
pow(exponent=):计算每个元素的exponent次幂(如pow(2)为平方)。
exp():计算每个元素的自然指数e^x。
数学模块辅助示例
import math
print(math.e) # 自然常数e
print(math.pi) # 圆周率π
print(math.sqrt(16)) # 平方根,结果4.0
print(math.log(math.e))# 自然对数,结果1.0
print(math.log(math.e, 2)) # 以2为底e的对数
print(math.log10(1000))# 以10为底1000的对数,结果3.0
print(math.log2(16)) # 以2为底16的对数,结果4.0
print(math.exp(1)) # e的1次幂,结果≈2.718
print(math.pow(2, 3)) # 2的3次幂,结果8.0
3.2.5 索引操作
核心作用:根据索引定位并获取张量中指定位置的数据,支持单元素、行列、切片、布尔索引等多种方式,核心语法为张量名[行索引, 列索引](多维张量可扩展为[0轴, 1轴, 2轴,...])。
基础索引方式
- 单独获取行列:
指定行:张量名[行索引, :](如data[1, :]获取第2行),可简化为张量名[行索引]。
- 指定列:张量名[:, 列索引](如data[:, 1]获取第2列),可简化为张量名[..., 1](...表示匹配所有前置维度)。
- 指定行列交点:张量名[行索引, 列索引](如data[2, 3]获取第3行第4列元素)。
批量获取多行列:
指定多行:张量名[[行索引1, 行索引2], :](如data[[0,2], :]获取第1、3行)。
指定多列:张量名[:, [列索引1, 列索引2]](如data[:, [0,2]]获取第1、3列)。
多行多列交集:张量名[[行1,行2], [列1,列2]](返回(行1,列1)、(行2,列2)的元素)。
多行多列子矩阵:张量名[[[行1],[行2]], [列1,列2]](返回行1-2与列1-2的交集子矩阵)。
切片获取连续数据:张量名[行切片, 列切片],切片语法为start:end:step(默认start=0, end=维度长度, step=1),如data[0:3, :]获取前3行。
布尔索引:张量名[布尔张量],仅保留布尔值为True的位置元素(如data[data>5]获取所有大于5的元素)。
多维张量索引:按轴顺序指定索引,如3维张量data[0, 1:3, 2]表示获取0轴第1个数据、1轴第2-3个数据、2轴第3个元素。
索引操作代码示例
import torch
# 设置随机种子保证结果可复现
torch.manual_seed(666)
# 创建4行5列的浮点型张量
data = torch.randint(1, 10, size=(4, 5), dtype=torch.float32)
print("原始张量:\n", data)
print("形状:", data.shape, "维度:", data.ndim)
print("="*50)
# 1. 单独获取行列
print("第2行数据:", data[1, :]) # 等价于data[1]
print("第2列数据:", data[:, 1]) # 等价于data[..., 1]
print("(2,3)位置元素:", data[1, 2])
print("="*50)
# 2. 批量获取多行列
print("第1、3行数据:\n", data[[0, 2], :])
print("第1、3列数据:\n", data[:, [0, 2]])
print("(0,0)和(2,2)位置元素:", data[[0,2], [0,2]])
print("第1、3行与第1、3列的交集子矩阵:\n", data[[[0],[2]], [0,2]])
print("="*50)
# 3. 切片获取连续数据
print("前3行数据:\n", data[:3, :])
print("前3列数据:\n", data[:, :3])
print("前3行前3列子矩阵:\n", data[:3, :3])
print("步长为2取数据:\n", data[0::2, 0::2]) # 行和列都按步长2取
print("="*50)
# 4. 布尔索引
print("大于5的元素:", data[data>5])
print("第1行大于5的元素:", data[0][data[0]>5])
print("第1列大于5的数据所在行:\n", data[data[:,0]>5, :])
3.2.6 形状操作
核心目标:在保持张量数据不变的前提下,调整其维度结构,适配不同运算需求。
shape与reshape
- tensor.shape:获取张量形状,与tensor.size()功能完全一致(如data.shape[0]获取行数)。
- tensor.reshape(shape=):修改张量形状,核心要求是“修改前后元素总数一致”;支持用-1自动计算某一维度长度(如(6,)->reshape(2,-1)自动得到(2,3)),可处理连续与非连续张量。
contiguous与view
- tensor.is_contiguous():判断张量在内存中是否连续存储。
- tensor.contiguous():将非连续张量转换为连续张量,通过复制数据实现。
- tensor.view(shape=):功能与reshape类似,但仅支持连续张量,非连续张量需先调用contiguous()。
squeeze与unsqueeze(降维与升维)
- 降维(squeeze):tensor.squeeze(dim=),默认删除所有维度值为1的维度;指定dim时仅删除该维度(若其值为1)。
- 升维(unsqueeze):tensor.unsqueeze(dim=),在指定维度插入一个值为1的维度;dim取值范围为[-当前维度数, 当前维度数](如1维张量dim可取值-2,-1,0,1)。
- 补充:通过索引也可升维,如tensor[None, :, None]在0轴和2轴各插入一个维度。
transpose与permute(维度交换)
- tensor.transpose(dim0, dim1):仅交换指定的两个维度(如3维张量transpose(0,1)交换0轴和1轴),交换后张量通常变为非连续。
- tensor.permute(dims=()):支持任意维度的重新排列(如3维张量permute(2,0,1)将2轴移到最前),灵活性更高,同样可能导致非连续。
形状操作代码示例
import torch
# 1. shape与reshape
t = torch.tensor([[1,2,3],[4,5,6]])
print("原始张量:", t)
print("形状:", t.shape, "size:", t.size())
print("reshape(3,2):", t.reshape(3,2))
print("reshape(1,6):", t.reshape(1,6))
print("reshape(6,1):", t.reshape(6,1))
print("="*50)
# 2. squeeze与unsqueeze
t1 = torch.tensor([1,2,3,4,5,6]) # 形状(6)
t2 = t1.unsqueeze(dim=0) # 形状(1,6)
t3 = t1.unsqueeze(dim=1) # 形状(6,1)
t4 = t2.squeeze() # 形状(6),恢复原始维度
print("升维(1,6):", t2.shape)
print("升维(6,1):", t3.shape)
print("降维后:", t4.shape)
print("="*50)
# 3. 多维张量维度交换
t5 = torch.randint(1,10, size=(2,3,4)) # 形状(2,3,4)
t6 = t5.transpose(0,2) # 交换0轴和2轴,形状变为(4,3,2)
t7 = t5.permute(2,0,1) # 重排维度为2,0,1,形状变为(4,2,3)
print("原始形状:", t5.shape)
print("transpose后形状:", t6.shape)
print("permute后形状:", t7.shape)
3.2.7 拼接操作
核心用于将多个结构相似的张量合并,分为“拼接(cat)”和“堆叠(stack)”两种方式,均需指定合并维度dim。
- torch.cat([t1, t2, ...], dim=):
核心规则:除合并维度dim外,其他维度的形状必须完全一致。
- 效果:在dim维度上拼接,不增加新维度,dim维度的长度为各张量对应维度长度之和(如两个(2,3)张量沿dim=0拼接后为(4,3))。
torch.stack([t1, t2, ...], dim=):
核心规则:所有输入张量的形状必须完全一致。
效果:在指定dim维度插入新维度,新维度的长度为输入张量的个数(如两个(2,3)张量沿dim=0堆叠后为(2,2,3))。
四、PyTorch框架核心模块
4.1 环境安装
pip install torch # 基础安装,根据系统自动匹配版本
# 如需指定CUDA版本,需参考PyTorch官网命令
4.2 自动微分模块(反向传播求梯度)
自动微分(Automatic Differentiation, AD)是PyTorch的核心特性,能够自动计算函数的导数(梯度),为神经网络反向传播提供基础。核心要求:参与梯度计算的张量必须是float类型,且创建时指定requires_grad=True。
核心原理
- 梯度的作用:通过梯度反映参数变化对损失函数的影响,用于更新模型权重(w)和偏置(b),找到最优参数。
- 参数更新公式:
(w0为旧参数,w1为新参数,lr为学习率,grad为梯度)。
- 关键注意点:反向传播时梯度会自动累加,每次迭代前需手动清零(w.grad.zero_()),避免梯度累积影响结果。
自动微分代码示例
import torch
# 示例1:单元素张量求梯度
x = torch.tensor([2.0], requires_grad=True) # 开启自动微分
y = x ** 3 # 定义函数y=x³
y.backward() # 反向传播求梯度
print("x=2时y=x³的梯度:", x.grad) # 结果tensor([12.]), 对应导数3x²=12
print("="*50)
# 示例2:多元素张量求梯度(需先将结果转为标量)
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x ** 3 # 结果为[8.0, 27.0],非标量
y.sum().backward() # 求和转为标量后求梯度
print("x=[2,3]时y=x³的梯度:", x.grad) # 结果tensor([12., 27.]), 对应3x²
print("="*50)
# 示例3:结合线性模型的梯度计算
x = torch.ones(2, 5) # 输入数据(2个样本,5个特征)
y = torch.zeros(2, 3) # 真实标签(2个样本,3个类别)
# 定义可学习参数(权重w和偏置b,均开启自动微分)
w = torch.randn(5, 3, requires_grad=True, dtype=torch.float)
b = torch.randn(3, requires_grad=True, dtype=torch.float)
# 计算预测值和损失
loss_fn = torch.nn.MSELoss() # 均方误差损失函数
z = x.matmul(w) + b # 线性模型z=wx+b
loss = loss_fn(z, y) # 计算损失
# 反向传播求梯度
if w.grad is not None:
w.grad.zero_() # 梯度清零(避免累积)
b.grad.zero_()
loss.backward() # 自动计算w和b的梯度
print("w的梯度:\n", w.grad)
print("b的梯度:\n", b.grad)
4.3 梯度问题:消失与爆炸
4.3.1 梯度消失(Vanishing Gradient)
深层网络中,反向传播时梯度通过链式求导不断连乘,若激活函数导数小于1(如sigmoid导数最大0.25),经过多层后梯度会趋近于0,导致浅层参数无法更新,模型训练停滞。
4.3.2 梯度爆炸(Exploding Gradient)
若权重初始化过大或激活函数导数大于1,反向传播时梯度会不断放大,导致参数更新幅度过大,模型权重异常,训练不稳定(如损失值变为NaN)。
解决思路
- 选用合适的激活函数(如ReLU)。
- 采用规范化的参数初始化方法(如He初始化、Xavier初始化)。
- 使用批量归一化(BatchNorm)稳定梯度。
- 限制梯度范围(如梯度裁剪)。
五、人工神经网络(ANN)核心技术
5.1 神经元结构与网络构成
5.1.1 单个神经元
核心构成:输入层(接收特征数据)→ 加权求和(输入与权重相乘后加偏置:z=wx+b)→ 激活函数(引入非线性:a=σ(z))→ 输出层(输出结果)。
5.1.2 多个神经元(神经网络)
由多层神经元组成,包括:输入层(接收原始数据)、隐藏层(提取特征)、输出层(输出预测结果)。层与层之间全连接(每个神经元与下一层所有神经元相连),即全连接神经网络(FCN)。
5.1.3 前向传播与反向传播
- 前向传播:从输入层到输出层,通过加权求和和激活函数计算预测值的过程,得到模型输出与损失值。
- 反向传播:从输出层到输入层,通过自动微分计算各层参数的梯度,利用梯度下降更新参数,最小化损失值。
5.2 激活函数(核心基础)
核心作用:为神经网络引入非线性因素,使模型能够拟合复杂的非线性关系(若缺少激活函数,多层网络与单层线性模型等价)。
常用激活函数对比
|
激活函数 |
值域 |
导数特性 |
优缺点 |
适用场景 |
|
Sigmoid |
[0,1] |
[0,0.25] |
优点:输出可表示概率;缺点:梯度消失严重,无负信号 |
二分类任务输出层 |
|
Tanh |
[-1,1] |
[0,1] |
优点:有负信号,梯度消失比Sigmoid慢;缺点:仍存在梯度消失 |
浅层网络隐藏层 |
|
ReLU |
[0,+∞) |
0或1 |
优点:梯度不消失,计算高效;缺点:存在“神经元死亡”问题 |
深层网络隐藏层(优先选择) |
|
Leaky ReLU |
(-∞,+∞) |
α或1(α为小常数) |
优点:解决ReLU的神经元死亡问题 |
深层网络隐藏层 |
|
Softmax |
[0,1](和为1) |
复杂(与交叉熵联合优化) |
优点:输出可表示多分类概率分布 |
多分类任务输出层 |
5.3 7大参数初始化方法
参数初始化是为模型权重(w)和偏置(b)设置初始值,核心目标:防止梯度消失/爆炸、打破神经元对称性(使各神经元学习不同特征)。偏置b通常初始化为0。
常用初始化方法及API
- 随机均匀初始化:torch.nn.init.uniform_(param),权重在均匀分布中随机取值。
- 随机正态分布初始化:torch.nn.init.normal_(param, mean=0, std=1),权重服从正态分布。
- 全0初始化:torch.nn.init.zeros_(param),适用于偏置b,权重不建议全0(打破对称性)。
- 全1初始化:torch.nn.init.ones_(param),需谨慎使用(易导致梯度问题)。
- 固定值初始化:torch.nn.init.constant_(param, value=),权重设为指定固定值。
- He(Kaiming)初始化:
API:kaiming_uniform_()、kaiming_normal_()。
- 特点:针对ReLU及其变体设计,仅考虑输入层维度,缓解ReLU负半轴输出为0的问题。
Xavier初始化:
API:xavier_uniform_()、xavier_normal_()。
特点:考虑输入和输出层维度,适用于Sigmoid、Tanh等激活函数。
初始化代码示例
import torch
# 创建一个线性层(输入3维,输出5维)
linear = torch.nn.Linear(in_features=3, out_features=5, bias=True)
# 1. 随机均匀初始化
torch.nn.init.uniform_(linear.weight)
print("随机均匀初始化权重:\n", linear.weight)
# 2. 正态分布初始化(均值0,标准差0.1)
torch.nn.init.normal_(linear.weight, mean=0, std=0.1)
print("正态分布初始化权重:\n", linear.weight)
# 3. 全0初始化(偏置常用)
torch.nn.init.zeros_(linear.bias)
print("偏置全0初始化:\n", linear.bias)
# 4. He正态初始化(适用于ReLU)
torch.nn.init.kaiming_normal_(linear.weight)
print("He正态初始化权重:\n", linear.weight)
# 5. Xavier均匀初始化(适用于Sigmoid)
torch.nn.init.xavier_uniform_(linear.weight)
print("Xavier均匀初始化权重:\n", linear.weight)
5.4 损失函数(核心基础)
损失函数(代价函数)用于衡量模型预测值与真实值的差异,是参数更新的“指挥棒”——损失值越小,模型性能越好。需根据任务类型(分类/回归)选择合适的损失函数。
分类任务损失函数
1. 多分类交叉熵损失(CrossEntropyLoss)
- 核心特性:内置Softmax激活函数,直接接收模型线性输出(logits),无需手动添加Softmax层。
- 适用场景:多分类任务(如手写数字识别,10个类别)。
- API:torch.nn.CrossEntropyLoss(reduction='mean')(reduction指定损失计算方式,mean为平均损失)。
import torch
# 真实标签(两种格式:热编码/类别索引)
y_true_hot = torch.tensor([[0,1,0],[0,0,1]], dtype=torch.float) # 热编码(推荐)
y_true_idx = torch.tensor([1,2], dtype=torch.int64) # 类别索引(直接对应热编码的1位置)
# 模型预测值(线性输出,未经过Softmax,开启自动微分)
y_pred = torch.tensor([[0.1,0.7,0.2],[0.1,0.3,0.6]], requires_grad=True, dtype=torch.float32)
# 计算损失
loss_fn = torch.nn.CrossEntropyLoss()
loss = loss_fn(y_pred, y_true_idx) # 传入类别索引更简洁
print("多分类交叉熵损失:", loss)
2. 二分类交叉熵损失(BCELoss)
- 核心特性:需手动在模型输出层添加Sigmoid激活函数,使预测值落在[0,1]区间。
- 适用场景:二分类任务(如垃圾邮件识别,是/否)。
- API:torch.nn.BCELoss(reduction='mean')。
import torch
# 真实标签(0/1)
y_true = torch.tensor([0,1,0], dtype=torch.float)
# 模型预测值(经过Sigmoid,开启自动微分)
y_pred = torch.tensor([0.1,0.7,0.2], requires_grad=True, dtype=torch.float32)
y_pred_sigmoid = torch.sigmoid(y_pred) # 手动添加Sigmoid
# 计算损失
loss_fn = torch.nn.BCELoss()
loss = loss_fn(y_pred_sigmoid, y_true)
print("二分类交叉熵损失:", loss)
回归任务损失函数
1. 平均绝对误差(MAE/L1Loss)
- 计算方式:预测值与真实值绝对误差的平均值,公式为 :
- 特点:对异常值鲁棒(异常值的绝对误差不会被平方放大),但在预测值与真实值相等处(0点)不可导,可能影响优化效率。
- 适用场景:数据中存在较多异常值的回归任务(如房价预测中的极端房价样本)。
- API:torch.nn.L1Loss(reduction='mean'),reduction可选"mean"(平均)、"sum"(求和)或"none"(返回每个样本的损失)。
2. 均方误差(MSE/L2Loss)
- 计算方式:预测值与真实值平方误差的平均值,公式为:
。
- 特点:对异常值敏感(异常值的误差会被平方放大),但处处可导,优化过程更平滑,是回归任务最常用的损失函数。
- 适用场景:数据分布相对均匀、异常值较少的回归任务(如气温预测、销售额预测)。
- API:torch.nn.MSELoss(reduction='mean'),参数与L1Loss一致。
3. HuberLoss(鲁棒损失函数)
- 核心特性:结合MAE和MSE的优势,通过超参数δ控制损失形式,是“鲁棒性”与“可导性”的折中方案。
- 分段损失形式:
当误差绝对值 ≤ δ时:采用MSE,公式为:,保证可导性。
- 当误差绝对值 > δ时:采用MAE的变形,公式为
- ,降低异常值影响。
- 适用场景:既需要平滑优化,又存在少量异常值的回归任务,δ通常取1.0(可根据数据调整)。
5.5 优化器:学习率与参数更新的核心(核心基础)
优化器的核心作用是根据损失函数的梯度,按照特定策略更新模型参数(w和b),最小化损失值。其核心参数是学习率(lr)——控制参数更新的步长,lr过大易导致参数震荡不收敛,lr过小则训练速度极慢。
5.5.1 优化器分类与核心原理
1. 基础优化器:SGD及其改进
- 随机梯度下降(SGD):
核心思想:每次使用一个批次(batch)的样本计算梯度,更新公式为(∇L(w)为损失对w的梯度)。
- 特点:计算量小、内存占用低,但梯度噪声大,参数更新路径震荡明显,可能陷入局部最优。
- 适用场景:数据量极大、对训练速度要求高的场景。
- API:torch.optim.SGD(params=[w, b], lr=0.01)。
- SGD+动量(Momentum):
核心思想:模拟物理“动量”概念,累加历史梯度的指数加权平均,降低更新震荡,公式为,
(γ为动量系数,通常取0.9)。
- 特点:加速收敛(沿梯度一致方向加速),抑制震荡,避免局部最优。
- API:torch.optim.SGD(params=[w, b], lr=0.01, momentum=0.9)。
2. 自适应学习率优化器(主流选择)
- Adagrad(自适应梯度):
核心思想:为不同参数分配不同学习率——参数梯度大则学习率小,梯度小则学习率大,公式为,(
为防止分母为0的小常数)。
- 特点:无需手动调整lr,初始学习率大、后期小;但历史梯度累加导致学习率过早衰减,训练后期可能停滞。
- 适用场景:高维稀疏数据(如文本分类、推荐系统)。
- API:torch.optim.Adagrad(params=[w, b], lr=0.01)。
- RMSprop(均方根传播):
核心思想:改进Adagrad,用“历史梯度的指数加权平均”替代“累加和”,缓解学习率衰减过快问题,公式为
,
(α通常取0.99)。
- 特点:保持自适应特性,训练稳定性优于Adagrad。
- 适用场景:高维稀疏数据、循环神经网络(RNN)。
- API:torch.optim.RMSprop(params=[w, b], lr=0.01, alpha=0.99)。
- Adam(自适应动量估计):
核心思想:融合“动量法”和“RMSprop”,同时考虑梯度的一阶矩(均值,对应动量)和二阶矩(方差,对应自适应学习率),是目前最常用的优化器。
- 特点:收敛快、稳定性好,无需手动调参,适用于绝大多数场景。
- API:torch.optim.Adam(params=[w, b], lr=0.01, betas=(0.9, 0.99))(betas分别为一阶矩和二阶矩的系数)。
- AdamW(Adam改进版):
核心思想:解耦Adam中的权重衰减(L2正则化)与自适应学习率,避免正则化效果被学习率稀释,公式为在Adam更新基础上单独添加权重衰减项(λ为权重衰减系数)。
- 特点:泛化能力优于Adam,是大模型训练的默认优化器(如BERT、GPT系列)。
- API:torch.optim.AdamW(params=[w, b], lr=0.01, weight_decay=1e-4)。
3. 学习率调整策略(手动干预)
当使用固定学习率的优化器时,可通过调度器(Scheduler)手动调整lr,核心思路是“前期大lr加速收敛,后期小lr精细优化”。
- 等间隔衰减(StepLR):
规则:每训练step_size个epoch,学习率乘以gamma衰减,公式为。
- API:torch.optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5)(每50轮lr减半)。
- 指定间隔衰减(MultiStepLR):
规则:在预设的milestones(如[50, 100, 160])轮次处,lr乘以gamma衰减,灵活性更高。
- API:torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[50,100], gamma=0.5)。
- 指数衰减(ExponentialLR):
规则:每轮epoch都按指数衰减,公式为,前期衰减快,后期衰减慢。
- API:torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)。
5.5.2 优化器使用流程代码示例
import torch
# 1. 定义可学习参数
w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)
b = torch.tensor([0.5], requires_grad=True, dtype=torch.float32)
# 2. 选择优化器(以AdamW为例)
optimizer = torch.optim.AdamW(params=[w, b], lr=0.01, weight_decay=1e-4)
# 3. 定义学习率调度器(StepLR)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.8)
# 4. 模拟训练循环
for epoch in range(20):
# 前向传播:假设简单线性模型 y = w*x + b,x=2,真实值y_true=5
x = torch.tensor([2.0])
y_pred = w * x + b
loss = torch.nn.MSELoss()(y_pred, torch.tensor([5.0])) # MSE损失
# 反向传播与参数更新
optimizer.zero_grad() # 梯度清零(必须!防止累积)
loss.backward() # 计算梯度
optimizer.step() # 更新参数
scheduler.step() # 调整学习率
# 打印日志
current_lr = optimizer.param_groups[0]['lr']
print(f"Epoch {epoch+1:2d} | Loss: {loss.item():.4f} | LR: {current_lr:.6f} | w: {w.item():.4f} | b: {b.item():.4f}")
5.6 正则化:解决过拟合的核心技术
过拟合是模型在训练集上表现极好,但在测试集上性能骤降的问题,核心原因是模型复杂度过高、学习了训练集的噪声。正则化通过在损失函数中添加“模型复杂度罚项”或引入随机机制,限制模型拟合能力,提升泛化性。
5.6.1 范数正则化(L1、L2)
核心思想:在原始损失函数基础上增加“权重范数”罚项,目标函数为 \( 目标函数 = 原始损失 + λ \times 正则化项 \)(λ为正则化强度,控制罚项权重)。
- L1正则化(L1 Norm):
数学形式:正则化项为权重的绝对值之和,即 \( L1 = \sum_{i}|w_i| \)。
- 核心作用:将部分权重压缩至0,产生“稀疏解”——忽略不重要的特征,实现特征选择。
- 特点:特征筛选能力强,但损失函数在权重为0处不可导,优化难度略高。
- L2正则化(L2 Norm/权重衰减):
数学形式:正则化项为权重的平方和,即 \( L2 = \sum_{i}w_i^2 \)。
- 核心作用:将权重均匀缩小但不置零,避免个别权重过大导致模型过拟合。
- 特点:损失函数可导,优化稳定,是工业界最常用的正则化方式(PyTorch中通过weight_decay参数实现)。
5.6.2 随机失活正则化(Dropout)
- 核心思想:训练时以概率p随机“关闭”部分神经元,使模型仅用剩余神经元学习特征,避免过度依赖某几个神经元。
- 关键机制:
训练时:失活神经元输出设为0,未失活神经元输出需除以(1-p),保证输入数据的期望不变。
- 测试时:关闭Dropout,所有神经元正常工作,无需调整输出。
- 注意事项:需通过model.train()(训练模式)和model.eval()(测试模式)切换Dropout状态。
- API与代码示例:
import torch # 1. 定义含Dropout的模型 class Net(torch.nn.Module): def __init__(self): super(Net, self).__init__() self.linear1 = torch.nn.Linear(4, 5) # 输入4维,隐藏层5维 self.dropout = torch.nn.Dropout(p=0.5) # 失活概率0.5 self.linear2 = torch.nn.Linear(5, 1) # 输出1维(回归任务) def forward(self, x): x = torch.relu(self.linear1(x)) # 线性层→激活函数 x = self.dropout(x) # 激活后使用Dropout(必须!) x = self.linear2(x) return x # 2. 测试Dropout效果 model = Net() x = torch.randn(1, 4) # 输入数据(1个样本,4个特征) # 训练模式:Dropout生效 model.train() print("训练模式Dropout输出(每次不同):", model(x).detach()) print("训练模式Dropout输出(再次运行):", model(x).detach()) # 测试模式:Dropout关闭 model.eval() print("测试模式输出(固定):", model(x).detach())
5.6.3 批量归一化(BatchNorm/BN)
BN是计算机视觉领域的常用正则化技术,核心目标是解决“内部协变量偏移(ICS)”——网络训练中各层输入分布随参数更新而变化的问题。
- 核心原理:对每一层的输入进行标准化,使其均值为0、方差为1,再通过可学习参数γ(缩放)和β(偏移)恢复特征表达能力,公式为:
计算批次均值:
- 计算批次方差:
- 标准化:
- 缩放偏移:
- 核心作用:
正则化:批次间的均值/方差差异引入轻微噪声,降低过拟合风险。
- 加速收敛:输入分布稳定,使激活函数(如Sigmoid)避免陷入梯度饱和区。
- 注意事项:
使用位置:线性层/卷积层之后、激活函数之前。
- 模式切换:训练时用批次统计,测试时用全局统计(通过model.eval()切换)。
- API选择:根据输入维度选择BatchNorm1d(1维数据,如文本)、BatchNorm2d(2维数据,如图像)、BatchNorm3d(3维数据,如视频)。
- 代码示例:
import torch # 定义含BatchNorm的模型(图像分类场景,用BatchNorm2d) class CNNNet(torch.nn.Module): def __init__(self): super(CNNNet, self).__init__() self.conv1 = torch.nn.Conv2d(3, 16, kernel_size=3) # 输入3通道,输出16通道 self.bn1 = torch.nn.BatchNorm2d(16) # 对应卷积层输出通道数 self.relu = torch.nn.ReLU() self.fc = torch.nn.Linear(16*28*28, 10) # 假设输入图像28×28 def forward(self, x): x = self.conv1(x) # 卷积层:(batch,3,32,32)→(batch,16,30,30) x = self.bn1(x) # BN层:在卷积后、激活前 x = self.relu(x) x = x.view(x.size(0), -1) # 展平:(batch,16,30,30)→(batch,16*30*30) x = self.fc(x) return x # 测试BN效果 model = CNNNet() x = torch.randn(2, 3, 32, 32) # 输入:2个样本,3通道,32×32图像 model.train() # 训练模式 print("BN输出形状:", model(x).shape) # 输出:(2,10)(2个样本,10分类)
六、综合案例:手机价格分类任务
本案例基于2000条电脑样本数据(20个特征,4类价格标签),实现从数据处理到模型训练、评估的完整流程,融合前文所学的正则化、优化器、损失函数等核心技术。
6.1 任务需求
- 任务类型:多分类任务(标签为0-3,对应4个价格区间)。
- 数据规模:2000条样本,划分训练集1600条、测试集400条。
- 核心目标:构建神经网络模型,实现电脑价格的精准分类,验证正则化与优化器的效果。
6.2 实现步骤
6.2.1 环境准备与数据加载
import torch
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 1. 加载数据(假设数据为csv格式,列名:feature_0~feature_19, price_label)
data = pd.read_csv("phone_price_data.csv")
X = data.iloc[:, :-1].values # 特征:前20列
y = data.iloc[:, -1].values # 标签:最后1列
# 2. 数据预处理:标准化(提升模型收敛速度)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 3. 划分训练集与测试集(随机种子保证可复现)
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.2, random_state=666
)
# 4. 转换为PyTorch张量
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.int64) # 多分类标签用int64
y_test = torch.tensor(y_test, dtype=torch.int64)
# 5. 构建数据集与数据加载器(批量训练)
train_dataset = torch.utils.data.TensorDataset(X_train, y_train)
test_dataset = torch.utils.data.TensorDataset(X_test, y_test)
train_loader = torch.utils.data.DataLoader(
train_dataset, batch_size=32, shuffle=True # 训练集打乱
)
test_loader = torch.utils.data.DataLoader(
test_dataset, batch_size=32, shuffle=False # 测试集不打乱
)
6.2.2 构建正则化神经网络模型
class PhonePriceNet(torch.nn.Module):
def __init__(self):
super(PhonePriceNet, self).__init__()
# 网络结构:输入层(20)→隐藏层1(64)→BN→Dropout→隐藏层2(32)→输出层(4)
self.fc1 = torch.nn.Linear(20, 64)
self.bn1 = torch.nn.BatchNorm1d(64) # 1维BN,对应隐藏层输出维度
self.dropout = torch.nn.Dropout(p=0.3) # 失活概率0.3
self.fc2 = torch.nn.Linear(64, 32)
self.fc3 = torch.nn.Linear(32, 4) # 输出4类,对应价格标签0-3
def forward(self, x):
# 前向传播:线性层→BN→激活→Dropout
x = self.fc1(x)
x = self.bn1(x)
x = torch.relu(x)
x = self.dropout(x)
x = self.fc2(x)
x = torch.relu(x)
x = self.fc3(x) # 输出logits,CrossEntropyLoss会自动加Softmax
return x
# 初始化模型
model = PhonePriceNet()
6.2.3 配置训练组件(损失函数、优化器)
# 1. 损失函数:多分类交叉熵(内置Softmax)
loss_fn = torch.nn.CrossEntropyLoss()
# 2. 优化器:AdamW(含L2正则化,weight_decay=1e-4)
optimizer = torch.optim.AdamW(
model.parameters(), lr=0.001, weight_decay=1e-4
)
# 3. 学习率调度器:每10轮衰减为原来的0.8
scheduler = torch.optim.lr_scheduler.StepLR(
optimizer, step_size=10, gamma=0.8
)
6.2.4 模型训练与日志记录
def train_model(model, train_loader, loss_fn, optimizer, scheduler, epochs=50):
model.train() # 切换训练模式(BN、Dropout生效)
best_acc = 0.0 # 记录最佳准确率
for epoch in range(epochs):
total_loss = 0.0
correct = 0
total = 0
# 遍历训练集批次
for X_batch, y_batch in train_loader:
# 前向传播
y_pred = model(X_batch)
loss = loss_fn(y_pred, y_batch)
# 反向传播与参数更新
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 统计损失与准确率
total_loss += loss.item() * X_batch.size(0)
_, predicted = torch.max(y_pred, dim=1) # 获取预测类别(argmax)
correct += (predicted == y_batch).sum().item()
total += y_batch.size(0)
# 调整学习率
scheduler.step()
# 计算本轮指标
epoch_loss = total_loss / total
epoch_acc = correct / total * 100
# 保存最佳模型(基于训练准确率)
if epoch_acc > best_acc:
best_acc = epoch_acc
torch.save(model.state_dict(), "best_phone_price_model.pth")
# 打印日志
print(f"Epoch {epoch+1:2d}/{epochs} | Loss: {epoch_loss:.4f} | Acc: {epoch_acc:.2f}% | Best Acc: {best_acc:.2f}%")
# 启动训练
train_model(model, train_loader, loss_fn, optimizer, scheduler, epochs=50)
6.2.5 模型评估与泛化能力验证
def evaluate_model(model, test_loader, loss_fn):
model.eval() # 切换测试模式(BN、Dropout关闭)
total_loss = 0.0
correct = 0
total = 0
# 禁用梯度计算(节省内存,加速评估)
with torch.no_grad():
for X_batch, y_batch in test_loader:
y_pred = model(X_batch)
loss = loss_fn(y_pred, y_batch)
# 统计指标
total_loss += loss.item() * X_batch.size(0)
_, predicted = torch.max(y_pred, dim=1)
correct += (predicted == y_batch).sum().item()
total += y_batch.size(0)
# 计算评估指标
avg_loss = total_loss / total
acc = correct / total * 100
print(f"\n测试集评估结果:")
print(f"平均损失:{avg_loss:.4f} | 准确率:{acc:.2f}%")
return acc
# 加载最佳模型参数
model.load_state_dict(torch.load("best_phone_price_model.pth"))
# 评估模型
test_acc = evaluate_model(model, test_loader, loss_fn)
6.3 案例关键说明
- 数据预处理:标准化(StandardScaler)消除特征量纲影响,是神经网络训练的必要步骤。
- 正则化融合:模型同时使用BN、Dropout和L2正则化(AdamW的weight_decay),多维度抑制过拟合。
- 模型保存:仅保存验证集准确率最高的模型参数,避免保存训练后期过拟合的模型。
- 评估优化:使用torch.no_grad()禁用梯度计算,大幅提升评估速度并减少内存占用。
七、核心知识点总结
7.1 技术选型速查表
|
任务场景 |
推荐技术 |
PyTorch API |
|
二分类任务 |
BCELoss + Sigmoid + AdamW |
nn.BCELoss(), torch.sigmoid(), optim.AdamW() |
|
多分类任务 |
CrossEntropyLoss + AdamW |
nn.CrossEntropyLoss(), optim.AdamW() |
|
回归任务(无异常值) |
MSELoss + AdamW |
nn.MSELoss(), optim.AdamW() |
|
回归任务(有异常值) |
MAE/HuberLoss + AdamW |
nn.L1Loss(), optim.AdamW() |
|
抑制过拟合(通用) |
Dropout + L2正则化 |
nn.Dropout(), optim.AdamW(weight_decay=1e-4) |
|
计算机视觉任务 |
BatchNorm2d + CNN + AdamW |
nn.BatchNorm2d(), nn.Conv2d() |
7.2 常见问题与解决方案
- 梯度消失:使用ReLU激活函数、He初始化、BatchNorm。
- 梯度爆炸:使用梯度裁剪(torch.nn.utils.clip_grad_norm_)、Xavier初始化。
- 过拟合:增加数据量、增强正则化(提高Dropout概率、增大weight_decay)、简化模型结构。
- 训练不收敛:调整学习率(增大/减小)、检查数据预处理(是否标准化)、检查标签格式(多分类标签是否为int64)。
本总结涵盖深度学习基础理论、PyTorch核心操作及实战案例,可作为入门到进阶的学习指南,实际应用中需根据具体任务调整技术选型与超参数。
1433

被折叠的 条评论
为什么被折叠?



