06 深度学习应用——《Python大数据实践(主编:吕欣 杨文川)》读书笔记
06 深度学习应用——《Python大数据实践(主编:吕欣 杨文川)》读书笔记
本文为《Python大数据实践(主编:吕欣 杨文川)》中“深度学习应用”相关内容的读书笔记。
本文主要围绕深度学习的基本思想、PyTorch 实践基础、常见神经网络结构、典型应用场景以及模型训练中的工程化问题展开。本文不是对教材内容的简单复述,而是在学习基础上结合个人理解进行重新整理和扩展。
一、对深度学习的整体认识
深度学习是机器学习中的重要分支,它的核心特点是通过多层神经网络自动学习数据中的特征表示。
在传统机器学习中,特征工程往往非常重要。
例如,在图像识别任务中,可能需要人工设计颜色、纹理、边缘、形状等特征;在文本分类任务中,可能需要人工构造词频、关键词、情感词典等特征。
而深度学习的优势在于,它可以直接从原始数据中学习特征。
例如:
- 在图像任务中,浅层网络可以学习边缘、颜色、纹理;
- 中间层网络可以学习局部结构;
- 深层网络可以学习更加抽象的语义信息;
- 在文本任务中,模型可以学习词语、句子和上下文之间的关系。
因此,我认为深度学习最重要的价值不是“模型层数更深”,而是它能够自动学习复杂数据中的表示方式。
二、深度学习解决了什么问题
深度学习主要适合处理传统方法较难表达的问题。
例如:
- 图像识别;
- 语音识别;
- 自然语言处理;
- 视频分析;
- 推荐系统;
- 时间序列预测;
- 图结构数据分析;
- 多模态数据理解。
这些任务的共同特点是数据结构复杂,人工特征设计难度较高。
以图像识别为例,一张图片不是简单的数字表格,而是由大量像素组成的空间结构。
如果完全依靠人工提取特征,很难覆盖不同光照、角度、姿态和背景下的变化。
深度学习通过神经网络自动学习特征,使模型能够更好地适应复杂数据。
三、深度学习与传统机器学习的区别
深度学习和传统机器学习并不是完全对立的关系,而是适用于不同场景。
| 对比维度 | 传统机器学习 | 深度学习 |
|---|---|---|
| 特征来源 | 依赖人工特征工程 | 自动学习特征 |
| 数据需求 | 中小规模数据也能使用 | 通常需要较多数据 |
| 模型复杂度 | 相对较低 | 较高 |
| 可解释性 | 通常较好 | 通常较弱 |
| 计算资源 | 资源需求较低 | 通常需要 GPU |
| 适合数据 | 结构化表格数据 | 图像、语音、文本、视频等非结构化数据 |
我的理解是:
传统机器学习更像是在“人设计好的特征”上学习规律;深度学习更像是让模型自己学习“什么特征有用”。
这也是深度学习能够在图像、语音和文本任务中取得突破的重要原因。
四、神经网络的基本结构
神经网络可以看作由多个神经元组成的计算模型。
一个简单的神经元可以表示为:
y=f(w1x1+w2x2+⋯+wnxn+b) y=f(w_1x_1+w_2x_2+\cdots+w_nx_n+b) y=f(w1x1+w2x2+⋯+wnxn+b)
其中:
- xix_ixi 表示输入特征;
- wiw_iwi 表示权重;
- bbb 表示偏置;
- fff 表示激活函数;
- yyy 表示输出结果。
神经网络通过不断调整权重和偏置,使模型输出逐渐接近真实标签。
从整体流程来看,神经网络训练包括:
- 前向传播;
- 计算损失;
- 反向传播;
- 参数更新。
五、前向传播与反向传播
前向传播是指数据从输入层经过隐藏层,最终得到输出结果的过程。
例如,在图像分类任务中,输入是一张图片,输出是每个类别的预测概率。
反向传播则是根据预测结果和真实标签之间的误差,反向计算每个参数对误差的影响,并更新模型参数。
简单来说:
- 前向传播负责“做预测”;
- 损失函数负责“判断错多少”;
- 反向传播负责“找到哪里错了”;
- 优化器负责“调整参数”。
这四个部分共同构成了深度学习训练的基本闭环。
六、激活函数的作用
如果神经网络中没有激活函数,那么多层线性变换最终仍然等价于一个线性模型。
因此,激活函数的作用是引入非线性能力,使神经网络能够拟合复杂关系。
常见激活函数包括:
| 激活函数 | 特点 | 常见用途 |
|---|---|---|
| Sigmoid | 输出范围在 0 到 1 之间 | 二分类早期常用 |
| Tanh | 输出范围在 -1 到 1 之间 | RNN 中较常见 |
| ReLU | 计算简单,缓解梯度消失 | CNN、MLP 常用 |
| Leaky ReLU | 避免部分神经元失活 | 深层网络 |
| Softmax | 输出类别概率分布 | 多分类任务输出层 |
其中,ReLU 是目前非常常用的激活函数之一。
import torch
import torch.nn as nn
activation = nn.ReLU()
x = torch.tensor([-1.0, 0.0, 2.0])
y = activation(x)
print(y)
输出结果中,负数会被变为 0,正数保持不变。
七、损失函数的作用
损失函数用于衡量模型预测值和真实值之间的差距。
不同任务需要选择不同的损失函数。
| 任务类型 | 常用损失函数 |
|---|---|
| 回归任务 | MSELoss、L1Loss |
| 二分类任务 | BCELoss、BCEWithLogitsLoss |
| 多分类任务 | CrossEntropyLoss |
| 图像分割 | Dice Loss、CrossEntropyLoss |
| 目标检测 | 分类损失 + 边界框回归损失 |
例如,多分类任务中常使用交叉熵损失:
import torch.nn as nn
criterion = nn.CrossEntropyLoss()
回归任务中常使用均方误差损失:
criterion = nn.MSELoss()
我的理解是:
损失函数决定了模型“努力优化的方向”。
如果损失函数选择不合适,模型即使训练很久,也可能无法得到理想结果。
八、优化器的作用
优化器负责根据梯度更新模型参数。
常见优化器包括:
| 优化器 | 特点 |
|---|---|
| SGD | 基础优化方法,稳定但可能收敛慢 |
| Momentum | 在 SGD 基础上加入动量 |
| RMSProp | 适合处理非平稳目标 |
| Adam | 自适应学习率,使用广泛 |
| AdamW | 在 Adam 基础上改进权重衰减 |
在实际深度学习任务中,Adam 和 AdamW 使用较多。
import torch.optim as optim
optimizer = optim.Adam(model.parameters(), lr=0.001)
优化器并不是越复杂越好。
有些任务中,SGD 配合合适的学习率调度也能取得非常好的效果。
九、PyTorch 的基本认识
PyTorch 是深度学习中常用的框架之一。
它的特点包括:
- 代码风格接近 Python;
- 支持动态计算图;
- 调试相对方便;
- 支持 GPU 加速;
- 社区资源丰富;
- 适合研究和工程实践。
PyTorch 中最基础的数据结构是张量 Tensor。
张量可以理解为多维数组,是神经网络中数据和参数的基本表示方式。
十、PyTorch 张量操作
创建张量:
import torch
x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print(x)
矩阵乘法:
y = torch.matmul(x, x.T)
print(y)
移动到 GPU:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
x = x.to(device)
张量是 PyTorch 的基础。
神经网络中的输入、权重、梯度和输出,本质上都可以看作张量。
十一、自动求导机制
PyTorch 的一个重要能力是自动求导。
只要设置 requires_grad=True,PyTorch 就可以追踪张量计算过程,并自动计算梯度。
import torch
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 1
y.backward()
print(x.grad)
这段代码会自动计算:
y=x2+3x+1 y=x^2+3x+1 y=x2+3x+1
对 xxx 的导数:
dydx=2x+3 \frac{dy}{dx}=2x+3 dxdy=2x+3
当 x=2x=2x=2 时,梯度为 7。
自动求导是神经网络反向传播的基础。
十二、构建一个简单神经网络
在 PyTorch 中,通常通过继承 nn.Module 构建模型。
import torch
import torch.nn as nn
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Linear(10, 32),
nn.ReLU(),
nn.Linear(32, 2)
)
def forward(self, x):
return self.net(x)
这个模型包含:
- 一个输入层;
- 一个隐藏层;
- 一个 ReLU 激活函数;
- 一个输出层。
虽然结构简单,但已经体现了神经网络的基本组成方式。
十三、模型训练的基本流程
一个完整的 PyTorch 训练流程通常包括:
- 准备数据;
- 构建模型;
- 定义损失函数;
- 定义优化器;
- 前向传播;
- 计算损失;
- 反向传播;
- 更新参数;
- 验证模型效果。
示例代码:
for epoch in range(num_epochs):
model.train()
for x_batch, y_batch in train_loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
outputs = model(x_batch)
loss = criterion(outputs, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("Epoch:", epoch, "Loss:", loss.item())
需要注意的是,optimizer.zero_grad() 很重要。
如果不清空梯度,PyTorch 会默认累积梯度,导致参数更新错误。
十四、全连接神经网络 MLP
MLP 是最基础的神经网络结构,也叫多层感知机。
它主要由多个全连接层组成,适合处理结构化特征或已经向量化的数据。
例如,手写数字识别中,可以将 28×28 的图像展平成 784 维向量,然后输入 MLP。
import torch.nn as nn
class MLP(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
x = x.view(x.size(0), -1)
return self.model(x)
MLP 的优点是结构简单,容易理解。
缺点是难以保留图像中的空间结构信息。
因此,在图像任务中,CNN 通常比 MLP 更合适。
十五、卷积神经网络 CNN
CNN 是图像任务中非常重要的神经网络结构。
它的核心思想包括:
- 局部感受野;
- 权值共享;
- 池化降采样;
- 多层特征提取。
卷积层可以提取图像局部区域的特征,例如边缘、角点和纹理。
随着网络加深,模型可以提取更加抽象的语义特征。
CNN 的优势在于,它能够保留图像空间结构,同时减少参数数量。
十六、CNN 简单示例
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(16, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Linear(32 * 7 * 7, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
return self.classifier(x)
这个模型可以用于简单的灰度图像分类任务。
其中:
Conv2d用于卷积特征提取;ReLU用于引入非线性;MaxPool2d用于降低特征图尺寸;Linear用于最终分类。
十七、CNN 的应用场景
CNN 常见应用包括:
- 图像分类;
- 目标检测;
- 图像分割;
- 人脸识别;
- 医学影像分析;
- 遥感影像识别;
- 缺陷检测。
CNN 适合图像任务,是因为图像具有明显的空间局部性。
相邻像素之间通常存在联系,而 CNN 可以利用这种局部结构。
我的理解是:
CNN 并不是简单地“看整张图”,而是先看局部,再逐渐组合成整体理解。
十八、循环神经网络 RNN
RNN 主要用于处理序列数据。
序列数据的特点是前后之间存在顺序关系,例如:
- 文本;
- 语音;
- 时间序列;
- 股票价格;
- 传感器数据。
RNN 的核心思想是引入隐藏状态,用来保存历史信息。
其基本形式可以表示为:
ht=tanh(Wxt+Uht−1+b) h_t=\tanh(Wx_t+Uh_{t-1}+b) ht=tanh(Wxt+Uht−1+b)
其中:
- xtx_txt 表示当前时刻输入;
- ht−1h_{t-1}ht−1 表示上一时刻隐藏状态;
- hth_tht 表示当前隐藏状态。
RNN 的问题是,当序列较长时,容易出现梯度消失或梯度爆炸,导致模型难以学习长期依赖关系。
十九、LSTM 与 GRU
为了解决普通 RNN 难以捕捉长期依赖的问题,出现了 LSTM 和 GRU。
LSTM 通过门控机制控制信息的保留和遗忘。
它包含输入门、遗忘门、输出门等结构。
GRU 是 LSTM 的简化版本,参数更少,训练速度通常更快。
二者都适合处理序列任务,例如:
- 文本分类;
- 机器翻译;
- 语音识别;
- 时间序列预测;
- 股票趋势预测。
简单来说:
RNN 适合短序列,LSTM 和 GRU 更适合长序列。
二十、LSTM 示例代码
import torch.nn as nn
class LSTMModel(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.lstm = nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=2,
batch_first=True
)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
output, (h_n, c_n) = self.lstm(x)
last_output = output[:, -1, :]
return self.fc(last_output)
在时间序列预测中,输入通常是一个时间窗口。
例如,用过去 30 天的数据预测第 31 天的数值。
二十一、Transformer 的基本认识
Transformer 是自然语言处理领域的重要模型结构,也逐渐扩展到图像、语音、多模态等领域。
Transformer 的核心机制是注意力机制,尤其是自注意力机制。
自注意力机制可以让模型在处理一个词时,同时关注句子中的其他词。
例如,对于句子:
我把苹果放进书包,因为它很重。
模型需要判断“它”指的是苹果还是书包。
注意力机制可以帮助模型建立词与词之间的联系。
二十二、Transformer 的优势
与 RNN 相比,Transformer 有几个明显优势:
- 更容易并行计算;
- 更擅长捕捉长距离依赖;
- 可以处理复杂上下文关系;
- 适合大规模预训练;
- 能够扩展到多模态任务。
Transformer 的出现推动了 BERT、GPT、T5、ViT 等模型的发展。
我的理解是:
RNN 是按顺序读句子,Transformer 是同时观察句子中各部分之间的关系。
这也是 Transformer 在 NLP 中表现突出的重要原因。
二十三、注意力机制的直观理解
注意力机制可以理解为模型在处理信息时的“重点选择”。
在图像中,模型可能更关注目标所在区域;
在文本中,模型可能更关注与当前词语相关的上下文;
在时间序列中,模型可能更关注关键时间点。
注意力机制的价值在于,它不是平均对待所有输入,而是学习哪些信息更重要。
这使模型具有更强的表达能力。
二十四、图神经网络 GNN
图神经网络用于处理图结构数据。
图结构由节点和边组成。
例如:
- 社交网络中,用户是节点,好友关系是边;
- 论文引用网络中,论文是节点,引用关系是边;
- 交通网络中,路口是节点,道路是边;
- 分子结构中,原子是节点,化学键是边。
传统神经网络擅长处理规则数据,例如图像和序列。
但图结构是不规则的,因此需要专门的图神经网络。
二十五、GNN 的基本思想
GNN 的核心思想是信息传播。
每个节点不仅使用自身特征,还会聚合邻居节点的信息。
可以简单理解为:
一个节点的表示,不只由自己决定,也由它周围的节点共同决定。
例如,在论文分类任务中,一篇论文的类别不仅与自身文本有关,也可能与它引用了哪些论文、被哪些论文引用有关。
常见 GNN 模型包括:
- GCN;
- GAT;
- GraphSAGE;
- GIN。
其中,GAT 引入注意力机制,可以为不同邻居分配不同重要性。
二十六、深度学习应用一:图像分类
图像分类是深度学习最典型的应用之一。
任务目标是让模型判断一张图片属于哪个类别。
例如:
- 猫狗分类;
- 手写数字识别;
- 遥感地物分类;
- 医学影像病灶识别;
- 工业产品缺陷识别。
图像分类的一般流程包括:
- 收集图像数据;
- 标注类别标签;
- 图像尺寸统一;
- 数据增强;
- 构建 CNN 或使用预训练模型;
- 训练模型;
- 评估准确率;
- 分析错误样本。
二十七、图像分类中的数据增强
数据增强是提升图像模型泛化能力的重要方法。
常见方法包括:
- 随机裁剪;
- 水平翻转;
- 颜色扰动;
- 随机旋转;
- 尺度缩放;
- 添加噪声。
PyTorch 示例:
from torchvision import transforms
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomHorizontalFlip(),
transforms.RandomRotation(10),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
])
数据增强的作用不是简单增加图片数量,而是让模型见到更多变化情况,从而减少过拟合。
二十八、迁移学习的价值
在图像任务中,如果数据量不大,从零训练深度模型通常效果不好。
此时可以使用迁移学习。
迁移学习的思想是:
利用在大规模数据集上训练好的模型,再针对自己的任务进行微调。
例如,可以使用 ResNet、VGG、EfficientNet 等预训练模型。
import torchvision.models as models
import torch.nn as nn
model = models.resnet18(weights="DEFAULT")
num_features = model.fc.in_features
model.fc = nn.Linear(num_features, 5)
这里将 ResNet 的最后分类层替换为适合自己任务的类别数量。
迁移学习的优势是:
- 减少训练时间;
- 降低数据需求;
- 提升模型效果;
- 适合中小规模数据集。
二十九、深度学习应用二:目标检测与实例分割
图像分类只需要判断图片属于哪一类。
但在很多场景中,我们还需要知道目标在哪里。
这就需要目标检测。
目标检测不仅要判断类别,还要输出目标位置。
例如,在监控图像中检测行人,需要输出行人的类别和边界框。
实例分割则进一步要求模型识别出目标的精确轮廓。
常见模型包括:
- Faster R-CNN;
- Mask R-CNN;
- YOLO;
- SSD;
- DETR。
三十、目标检测的实践难点
目标检测比图像分类更复杂,主要难点包括:
- 图像中目标数量不固定;
- 目标大小差异较大;
- 目标可能发生遮挡;
- 背景干扰较多;
- 标注成本较高;
- 实时检测对速度要求高。
例如,在行人检测中,一个人可能只露出半个身体,也可能被其他物体遮挡。
这就要求模型不仅能识别完整目标,也能识别局部可见目标。
在工程应用中,目标检测模型需要在准确率和推理速度之间平衡。
三十一、深度学习应用三:时间序列预测
时间序列预测是深度学习的重要应用方向之一。
常见任务包括:
- 股票价格预测;
- 电力负荷预测;
- 交通流量预测;
- 气象数据预测;
- 设备状态预测;
- 用户行为趋势预测。
时间序列数据具有明显的时间依赖性。
当前状态往往与过去一段时间有关。
LSTM、GRU、Temporal CNN 和 Transformer 都可以用于时间序列建模。
三十二、时间序列预测的注意事项
时间序列预测不能像普通数据一样随机打乱。
因为时间顺序本身包含重要信息。
在划分训练集和测试集时,应按照时间顺序划分:
前 70% 时间段:训练集
中间 15% 时间段:验证集
后 15% 时间段:测试集
如果随机划分,可能会出现未来信息泄露,导致模型评估结果虚高。
这是时间序列建模中非常容易忽视的问题。
三十三、时间窗口构造示例
使用过去若干天数据预测下一天,可以构造滑动窗口。
import numpy as np
def build_windows(data, window_size):
X = []
y = []
for i in range(window_size, len(data)):
X.append(data[i-window_size:i])
y.append(data[i])
return np.array(X), np.array(y)
例如,使用过去 30 天预测第 31 天:
X, y = build_windows(data, window_size=30)
这种方式把时间序列问题转化为了监督学习问题。
三十四、深度学习应用四:自然语言处理
自然语言处理主要研究如何让计算机理解和生成文本。
常见任务包括:
- 文本分类;
- 情感分析;
- 机器翻译;
- 文本摘要;
- 命名实体识别;
- 问答系统;
- 文本生成。
早期 NLP 方法依赖词袋模型、TF-IDF、Word2Vec 等技术。
现在,BERT、GPT 等预训练语言模型成为主流方法。
三十五、情感分析任务理解
情感分析是文本分类中的典型任务。
例如,判断一句评论是正面还是负面:
这家酒店位置很好,服务也很热情。
可以判断为正面。
房间很吵,卫生也不好。
可以判断为负面。
情感分析看似简单,但实际存在很多难点:
- 反讽表达;
- 否定词;
- 语境依赖;
- 行业词汇;
- 多情感混合;
- 短文本信息不足。
例如:
这服务真是太“贴心”了。
如果结合上下文,可能实际表达的是不满。
三十六、BERT 微调基本流程
BERT 是一种基于 Transformer 的预训练语言模型。
在具体任务中,可以在预训练模型基础上进行微调。
基本流程包括:
- 加载分词器;
- 对文本进行编码;
- 加载预训练模型;
- 添加分类层;
- 在任务数据上训练;
- 评估模型效果。
示例代码:
from transformers import BertTokenizer, BertForSequenceClassification
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = BertForSequenceClassification.from_pretrained(
"bert-base-chinese",
num_labels=2
)
文本编码:
encoded = tokenizer(
texts,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt"
)
BERT 的优势在于能够结合上下文理解词语含义。
这比传统词袋模型更适合复杂文本理解任务。
三十七、深度学习应用五:机器翻译
机器翻译是自然语言处理中的重要任务。
早期机器翻译依赖规则和统计方法。
后来,RNN、LSTM 和 Seq2Seq 模型推动了神经机器翻译的发展。
现在,Transformer 成为机器翻译中的核心结构。
机器翻译的难点包括:
- 词序差异;
- 一词多义;
- 长句依赖;
- 文化语境;
- 低资源语言;
- 专业术语翻译。
例如,中文和英文的语序差异较大,直接逐词翻译往往效果不好。
Transformer 通过注意力机制,可以更好地建立源语言和目标语言之间的对应关系。
三十八、深度学习应用六:图结构数据分析
图结构数据在现实中非常常见。
例如:
- 社交网络;
- 推荐系统;
- 交通网络;
- 知识图谱;
- 分子结构;
- 论文引用网络。
在图结构任务中,模型不仅要考虑节点自身特征,还要考虑节点之间的连接关系。
常见任务包括:
- 节点分类;
- 边预测;
- 图分类;
- 社区发现;
- 链路预测。
图神经网络的价值在于,它能把结构信息和特征信息结合起来。
三十九、图注意力网络 GAT 的理解
GAT 在 GNN 中引入注意力机制。
它不是简单平均邻居信息,而是学习不同邻居的重要程度。
例如,在论文引用网络中,一篇论文可能引用很多论文,但并不是每篇引用论文对当前论文分类都同等重要。
GAT 可以自动学习哪些邻居节点更关键。
这种思想与人类判断类似:
不同关系的重要性不同,模型应该学会区分。
四十、深度学习应用七:风格迁移
风格迁移是一种有趣的深度学习应用。
它的目标是将一张图片的内容和另一张图片的风格结合起来。
例如:
- 内容图像是一张城市照片;
- 风格图像是一幅油画;
- 生成图像保留城市结构,同时具有油画风格。
风格迁移通常会使用预训练 CNN 提取图像特征。
其中:
- 内容损失用于保留原图结构;
- 风格损失用于学习风格图像的纹理和色彩;
- 总损失用于平衡内容和风格。
四十一、Gram 矩阵的直观理解
在风格迁移中,Gram 矩阵常用于表示风格信息。
它可以衡量不同特征通道之间的相关性。
简单来说:
内容关注“图中有什么”,风格关注“它看起来像什么”。
示例代码:
import torch
def gram_matrix(feature):
batch, channels, height, width = feature.size()
feature = feature.view(batch * channels, height * width)
gram = torch.mm(feature, feature.t())
return gram / (batch * channels * height * width)
通过比较生成图像和风格图像的 Gram 矩阵,可以让生成图像逐渐接近目标风格。
四十二、深度学习训练中的过拟合问题
过拟合是深度学习中常见问题。
表现为:
- 训练集效果很好;
- 验证集或测试集效果较差。
原因可能包括:
- 模型过于复杂;
- 数据量太少;
- 数据噪声较大;
- 训练轮数过多;
- 数据增强不足;
- 正则化不足。
解决方法包括:
- 增加数据;
- 数据增强;
- Dropout;
- L2 正则化;
- Early Stopping;
- 降低模型复杂度;
- 使用预训练模型;
- 交叉验证。
四十三、Dropout 的作用
Dropout 是防止过拟合的常用方法。
它在训练过程中随机丢弃部分神经元,使模型不能过度依赖某些特定节点。
import torch.nn as nn
layer = nn.Dropout(p=0.5)
在训练时,Dropout 会随机让部分神经元输出为 0。
在测试时,Dropout 不再随机丢弃神经元。
我的理解是:
Dropout 相当于让模型不要只依赖少数“熟人”,而是学会从更多特征中做判断。
四十四、Batch Normalization 的作用
Batch Normalization 用于稳定神经网络训练过程。
它可以对中间层输出进行标准化,使数据分布更加稳定。
优点包括:
- 加快训练速度;
- 缓解梯度消失;
- 使模型对初始化不那么敏感;
- 具有一定正则化效果。
示例:
import torch.nn as nn
bn = nn.BatchNorm2d(32)
在 CNN 中,BatchNorm 常放在卷积层之后、激活函数之前或之后。
四十五、学习率调度
学习率是深度学习训练中非常重要的超参数。
学习率太大,模型可能震荡甚至无法收敛。
学习率太小,模型训练速度很慢,也可能陷入局部最优。
常见学习率策略包括:
- 固定学习率;
- 分段衰减;
- 指数衰减;
- 余弦退火;
- 学习率预热。
PyTorch 示例:
scheduler = torch.optim.lr_scheduler.StepLR(
optimizer,
step_size=10,
gamma=0.1
)
在每轮训练后更新学习率:
scheduler.step()
学习率调度的作用是让模型在训练初期快速学习,在训练后期稳定收敛。
四十六、早停机制 Early Stopping
Early Stopping 是防止过拟合的常用方法。
它的思想是:
如果验证集效果连续多轮没有提升,就提前停止训练。
这样可以避免模型在训练集上继续过度拟合。
简单逻辑如下:
best_loss = float("inf")
patience = 5
counter = 0
for epoch in range(num_epochs):
val_loss = evaluate(model, val_loader)
if val_loss < best_loss:
best_loss = val_loss
counter = 0
torch.save(model.state_dict(), "best_model.pth")
else:
counter += 1
if counter >= patience:
print("Early stopping")
break
早停机制在数据量有限时非常实用。
四十七、模型评估指标
不同任务需要不同的评估指标。
分类任务常用:
- Accuracy;
- Precision;
- Recall;
- F1-score;
- AUC。
回归任务常用:
- MAE;
- MSE;
- RMSE;
- R²。
目标检测常用:
- IoU;
- mAP;
- Precision;
- Recall。
机器翻译常用:
- BLEU;
- ROUGE;
- METEOR。
不能只看一个指标。
例如,在类别不平衡任务中,Accuracy 可能很高,但模型可能只是倾向预测多数类。
四十八、深度学习中的数据质量问题
深度学习虽然强大,但对数据质量非常敏感。
常见数据问题包括:
- 标签错误;
- 样本数量不足;
- 类别不平衡;
- 数据分布偏移;
- 重复数据过多;
- 训练集与测试集差异过大;
- 数据泄露。
例如,在图像分类中,如果训练集背景与类别高度绑定,模型可能学到的是背景,而不是目标本身。
比如,所有猫图片都在室内,所有狗图片都在户外,模型可能实际上是在区分室内和户外。
因此,深度学习不是只要把数据丢进模型就可以,还需要认真检查数据。
四十九、深度学习工程实践流程
我认为,一个完整的深度学习项目可以按照以下流程进行:
- 明确任务目标;
- 收集数据;
- 检查数据质量;
- 划分训练集、验证集和测试集;
- 进行数据预处理;
- 构建基线模型;
- 选择合适网络结构;
- 设置损失函数和优化器;
- 训练模型;
- 观察训练曲线;
- 调整超参数;
- 分析错误样本;
- 保存最优模型;
- 部署模型;
- 持续监控模型效果。
其中,错误样本分析非常重要。
它可以帮助我们判断模型到底错在哪里。
五十、训练曲线的分析
训练过程中,通常需要观察训练集和验证集的损失曲线。
如果训练损失下降,验证损失也下降,说明模型正常学习。
如果训练损失下降,但验证损失上升,说明可能过拟合。
如果训练损失和验证损失都很高,说明模型可能欠拟合。
如果损失曲线剧烈震荡,可能是学习率过大。
因此,训练曲线是判断模型状态的重要依据。
五十一、模型部署与压缩
深度学习模型训练完成后,还需要考虑部署问题。
部署时常见挑战包括:
- 模型体积太大;
- 推理速度太慢;
- 设备算力有限;
- 显存或内存不足;
- 不同框架兼容问题;
- 线上数据分布变化。
常见优化方法包括:
- 模型剪枝;
- 模型量化;
- 知识蒸馏;
- ONNX 转换;
- TensorRT 加速;
- 使用轻量化模型。
例如,移动端部署时,可能更适合 MobileNet、ShuffleNet 等轻量模型。
五十二、可解释性问题
深度学习模型经常被认为是“黑箱”。
模型虽然能给出预测结果,但不一定容易解释为什么这样预测。
在一些高风险场景中,可解释性非常重要。
例如:
- 医疗诊断;
- 金融风控;
- 自动驾驶;
- 法律辅助;
- 安全监控。
常见可解释方法包括:
- Grad-CAM;
- LIME;
- SHAP;
- Attention 可视化;
- 特征重要性分析。
可解释性可以帮助研究者发现模型是否真的学到了合理特征。
五十三、深度学习的局限性
深度学习虽然强大,但并不是万能方法。
它存在以下局限:
- 需要大量数据;
- 训练成本较高;
- 模型解释性较弱;
- 对数据分布变化敏感;
- 容易受到对抗样本影响;
- 调参成本较高;
- 小数据场景下不一定优于传统方法。
因此,在实际应用中,不能盲目使用深度学习。
如果任务是结构化表格数据,并且样本量不大,随机森林、XGBoost、LightGBM 等传统机器学习模型可能更加合适。
五十四、不同任务的模型选择建议
| 任务类型 | 可选模型 | 说明 |
|---|---|---|
| 图像分类 | CNN、ResNet、ViT | 数据少时建议迁移学习 |
| 目标检测 | YOLO、Faster R-CNN、Mask R-CNN | 需要关注速度和精度 |
| 文本分类 | BERT、TextCNN、Transformer | 中文任务可使用中文预训练模型 |
| 时间序列预测 | LSTM、GRU、Transformer | 注意时间顺序划分 |
| 图结构任务 | GCN、GAT、GraphSAGE | 适合社交网络和知识图谱 |
| 回归预测 | MLP、LSTM、GBDT | 需根据数据类型选择 |
| 多模态任务 | CLIP、跨模态 Transformer | 适合图文结合任务 |
模型选择不能只看模型是否先进,而要结合数据规模、任务类型、计算资源和部署要求。
五十五、深度学习学习路线
结合本章内容,我认为学习深度学习可以按照以下顺序:
- Python 基础;
- NumPy 和 Pandas;
- 机器学习基础;
- 神经网络基本原理;
- PyTorch 张量和自动求导;
- MLP;
- CNN;
- RNN、LSTM、GRU;
- Transformer;
- GNN;
- 模型训练技巧;
- 项目实践;
- 模型部署与优化。
学习深度学习不能只看理论,也不能只跑代码。
比较好的方式是:
理解原理 + 阅读代码 + 跑通案例 + 修改实验 + 总结错误。
五十六、本章学习总结
通过本章学习,我认识到深度学习是一种以神经网络为基础的表示学习方法。
它最大的优势是能够从数据中自动提取特征,特别适合处理图像、文本、语音、视频和图结构等复杂数据。
PyTorch 为深度学习实践提供了方便的工具。
通过张量、自动求导、神经网络模块、损失函数和优化器,可以较为清晰地完成模型构建与训练。
不同神经网络结构适合不同任务:
- MLP 适合基础向量数据;
- CNN 适合图像和空间结构数据;
- RNN、LSTM、GRU 适合序列数据;
- Transformer 适合文本和长距离依赖任务;
- GNN 适合图结构数据。
同时,深度学习实践并不只是搭建模型。
数据质量、损失函数、优化器、学习率、正则化、评估指标、过拟合控制和模型部署都非常重要。
本章给我的启发是:深度学习不是“越深越好”,也不是“模型越复杂越好”,而是要根据任务特点选择合适的方法。
五十七、个人理解
我认为,深度学习真正重要的地方不只是算法本身,而是它改变了我们处理数据的方式。
传统方法更依赖人工经验,需要人先设计特征,再交给模型学习。
深度学习则尝试让模型自己从数据中学习有效表示。
这种变化使得模型能够处理更加复杂的数据,例如图片、语音、文本和图结构。
但是,深度学习也不是万能的。
如果数据量不足、标签质量差、训练集和测试集分布不一致,那么再复杂的模型也可能得不到可靠结果。
因此,我认为深度学习项目中最重要的不是直接追求高准确率,而是建立完整的建模思维:
- 先理解任务;
- 再理解数据;
- 再选择模型;
- 再优化训练过程;
- 最后分析错误原因。
其中,错误分析非常关键。
它能帮助我们判断模型失败是因为数据问题、模型问题、参数问题,还是任务本身存在困难。
我的总结是:
深度学习的本质不是堆叠网络层数,而是通过数据、模型和优化方法共同学习有效表示。
只有理解这一点,才能真正把深度学习应用到实际问题中。
五十八、参考代码汇总
1. 创建张量
import torch
x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print(x)
2. 自动求导
import torch
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 1
y.backward()
print(x.grad)
3. 简单 MLP 模型
import torch.nn as nn
class MLP(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
x = x.view(x.size(0), -1)
return self.model(x)
4. 简单 CNN 模型
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(16, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Linear(32 * 7 * 7, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
return self.classifier(x)
5. LSTM 模型
import torch.nn as nn
class LSTMModel(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.lstm = nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=2,
batch_first=True
)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
output, _ = self.lstm(x)
last_output = output[:, -1, :]
return self.fc(last_output)
6. 数据增强
from torchvision import transforms
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomHorizontalFlip(),
transforms.RandomRotation(10),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
])
7. 加载预训练模型
import torchvision.models as models
import torch.nn as nn
model = models.resnet18(weights="DEFAULT")
num_features = model.fc.in_features
model.fc = nn.Linear(num_features, 5)
8. 定义损失函数
import torch.nn as nn
criterion = nn.CrossEntropyLoss()
9. 定义优化器
import torch.optim as optim
optimizer = optim.Adam(model.parameters(), lr=0.001)
10. 模型训练循环
for epoch in range(num_epochs):
model.train()
for x_batch, y_batch in train_loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
outputs = model(x_batch)
loss = criterion(outputs, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("Epoch:", epoch, "Loss:", loss.item())
11. 学习率调度
scheduler = torch.optim.lr_scheduler.StepLR(
optimizer,
step_size=10,
gamma=0.1
)
for epoch in range(num_epochs):
train_one_epoch()
scheduler.step()
12. Early Stopping 示例
best_loss = float("inf")
patience = 5
counter = 0
for epoch in range(num_epochs):
val_loss = evaluate(model, val_loader)
if val_loss < best_loss:
best_loss = val_loss
counter = 0
torch.save(model.state_dict(), "best_model.pth")
else:
counter += 1
if counter >= patience:
print("Early stopping")
break
13. BERT 文本分类模型
from transformers import BertTokenizer, BertForSequenceClassification
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = BertForSequenceClassification.from_pretrained(
"bert-base-chinese",
num_labels=2
)
14. BERT 文本编码
encoded = tokenizer(
texts,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt"
)
15. Gram 矩阵
import torch
def gram_matrix(feature):
batch, channels, height, width = feature.size()
feature = feature.view(batch * channels, height * width)
gram = torch.mm(feature, feature.t())
return gram / (batch * channels * height * width)
16. 模型保存
torch.save(model.state_dict(), "model.pth")
17. 模型加载
model.load_state_dict(torch.load("model.pth"))
model.eval()
五十九、结语
深度学习应用范围非常广,从图像分类、目标检测,到自然语言处理、时间序列预测和图神经网络,都可以看到深度学习的作用。
但在实际学习和使用中,不能只关注模型名称,也不能只追求复杂网络结构。
更重要的是理解数据特点、任务目标、训练过程和模型评估方法。
深度学习真正的价值,不只是提高预测准确率,而是为复杂数据提供了一种自动表示学习的方法。
这也是本章对我最大的启发。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)