最近学习了深度学习,感觉内容非常丰富,目前还在消化吸收中。写这篇博客主要是为了梳理我这几天所学,记录学习足迹,也欢迎各位读者指出不足之处!
一、 什么是深度学习:特征提取的艺术
简单来说,深度学习是机器学习的一个分支,其核心在于如何让机器自动地从数据中学习和提取有效的特征,进而完成复杂的任务(如分类、识别、预测等)。
举个例子:为了实现为每个用户推送最合适的抖音视频内容,我们可以构建一个神经网络模型。这个模型的输入是用户历史观看行为数据(数据中蕴含海量特征),输出则是模型学习到的、代表用户对不同内容特征偏好程度的权重(例如,特征A占30%,特征B占50%...)。后续推送就可以侧重这些高权重特征相关的视频。
那么,这个模型是如何构建和工作的呢?
- 模型基础: 类似于函数
y = w * x + b
。数据x
输入模型,经过一系列计算得到输出y
。 - 参数学习:
w
(权重参数) 决定了输入特征x
对结果y
的影响大小(w
越大,该特征越重要);b
(偏置项) 是模型的偏移量。 - 训练过程: 如何让模型预测更准确?需要输入大量的训练数据进行训练 。
- 初始化: 首先构建模型的基本框架(网络结构),其中的
w
和b
初始值通常随机生成。 - 前向传播: 将训练数据输入模型,数据流经网络各层进行计算,最终得到预测输出
y_pred
。 - 计算损失: 将模型的预测输出
y_pred
与真实的标签y_true
进行比较,使用损失函数 (如均方误差MSE、交叉熵CrossEntropy)计算它们之间的差异(损失值loss
)。 - 反向传播: 核心步骤!利用链式法则,计算损失函数
loss
相对于模型每个参数(w
,b
)的梯度 (偏导数∂loss/∂w
,∂loss/∂b
)。梯度指示了参数需要调整的方向和幅度(减少loss
的方向)。 - 参数更新: 使用优化器 (如SGD, Adam)根据计算出的梯度更新模型的
w
和b
值(例如:w = w - learning_rate * ∂loss/∂w
)。
- 初始化: 首先构建模型的基本框架(网络结构),其中的
- 迭代优化: 重复执行前向传播->计算损失->反向传播->更新参数这个过程数千次甚至上万次(称为"迭代"或"轮次"),模型参数(
w
,b
)会逐渐调整到最优状态,使得模型在训练数据上的预测越来越准确(损失越来越小)。
总结: 深度学习就是通过设计神经网络结构,利用大量的数据和反向传播算法,不断迭代优化模型内部的参数(w
, b
),最终让模型具备强大的、自动化的特征提取和模式识别 能力。整个过程的核心就是"前向传播计算输出 -> 计算损失 -> 反向传播计算梯度 -> 优化器更新参数"的循环。
二、 模型搭建的关键要素
1. 数据预处理:模型的基石
原始数据通常五花八门,格式各异。在输入模型之前,必须进行数据预处理:
- 数据清洗: 处理缺失值、去除异常值或无效数据、处理重复数据等。
- 标准化/归一化: 将不同尺度的特征缩放到一个相对统一的范围内(如[0, 1]或均值为0、方差为1)。这能显著加速模型收敛并提高性能。
- 数据集划分: 将处理后的数据划分为:
- 训练集 (Training Set): 用于训练模型参数(占比最大,如70%)。
- 验证集 (Validation Set): 用于在训练过程中监控模型性能、调整超参数(如学习率、网络层数)和进行早停(Early Stopping)以防止过拟合(如20%)。
- 测试集 (Test Set): 用于在模型训练和调优完成后,最终、独立地评估模型的泛化能力(如10%)。比例(如7:2:1)可根据数据量和任务调整。
2. 神经网络的核心:层 (Layers)
搭建模型的核心是定义神经网络的层结构。一个神经网络必然包含:
- 输入层 (Input Layer): 接收原始数据。其大小(神经元数量)由输入数据的维度决定(例如,一张28x28的灰度图像展开成784个像素点输入,对应784个神经元)。
- 输出层 (Output Layer): 产生模型的最终预测结果。其大小和激活函数由任务性质决定(例如,10分类任务通常有10个神经元,使用Softmax激活)。
- 隐藏层 (Hidden Layers): 位于输入层和输出层之间。层数和每层的神经元数量(宽度)由我们设计决定。它们是模型学习特征表示的核心部分。
层与层之间的连接: 通常,前一层的所有神经元(数量记为 x
)会连接到下一层的所有神经元(数量记为 y
)。这会产生 x * y
个权重参数 (w
) 和 y
个偏置参数 (b
)。
常见的隐藏层类型:
-
全连接层 (Fully Connected Layer / Dense Layer)
-
作用: 对输入数据进行线性变换 (
y = w*x + b
) 后接非线性激活函数(如ReLU、Sigmoid、Tanh),提取更高级别的特征。是网络中最基础的层类型。 -
结构: 每个神经元的输出是前一层所有神经元输入的加权和 + 偏置项,再通过激活函数。
-
应用场景: 处理一维特征向量(如图像分类任务中卷积层提取特征后的向量、自然语言处理中的词嵌入向量)。
-
PyTorch 示例:
pythonimport torch.nn as nn fc_layer = nn.Linear(in_features=128, out_features=64) # 输入128维,输出64维
-
-
卷积层 (Convolutional Layer)
-
作用: 卷积神经网络(CNN)的核心。使用卷积核(滤波器) 在输入数据(通常是图像)上滑动,提取局部空间特征(如边缘、纹理)。模拟了人类视觉系统逐层提取特征的过程。卷积核的数量决定了输出特征图的通道数(深度)。
-
结构: 输入数据(如H x W x C的图像)与卷积核进行卷积运算,生成特征图(Feature Map)。每个卷积核学习提取一种特定的局部特征模式。
-
应用场景: 图像处理、计算机视觉(图像分类、目标检测、语义分割等)。
-
PyTorch 示例与参数详解:
pythonimport torch.nn as nn # 定义一个卷积层: 输入3通道(如RGB图像), 输出16个特征图(即用16个卷积核), 卷积核大小3x3, 滑动步长1, 边缘填充1圈(保持尺寸) conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1) # 输出尺寸计算 (假设输入尺寸 H_in x W_in): # H_out = floor((H_in + 2*padding - kernel_size) / stride) + 1 # W_out = floor((W_in + 2*padding - kernel_size) / stride) + 1 # 当 padding = kernel_size // 2 且 stride=1 时,通常能保持 H_out = H_in, W_out = W_in。
in_channels
: 输入数据的通道数 (C_in)。RGB图像为3,灰度图为1。out_channels
: 输出特征图的通道数/数量 (C_out)。即使用的卷积核数量。kernel_size
: 卷积核的空间尺寸(高度x宽度)。整数表示正方形核。stride
: 卷积核在输入上滑动的步长。控制输出特征图尺寸的缩减程度。padding
: 在输入数据边缘填充的像素圈数(通常用0填充)。常用于控制输出特征图尺寸,特别当stride=1
时,padding=1
配合kernel_size=3
可保持输入输出宽高不变。
-
-
池化层 (Pooling Layer)
-
作用: 通常跟在卷积层后。对局部区域进行下采样 ,降低特征图的空间分辨率(宽度和高度),减少计算量和参数数量 ,同时保留重要特征(如最大池化保留最显著特征),并赋予模型一定的平移不变性。
-
结构:
- 最大池化 (Max Pooling): 取局部区域内的最大值。
- 平均池化 (Average Pooling): 取局部区域内的平均值。
-
应用场景: 图像处理、计算机视觉任务。
-
PyTorch 示例:
pythonimport torch.nn as nn # 定义一个最大池化层: 池化窗口2x2, 滑动步长2 (通常步长等于窗口大小,实现减半下采样) max_pool_layer = nn.MaxPool2d(kernel_size=2, stride=2)
-
-
循环层 (Recurrent Layer)
-
作用: 循环神经网络(RNN)的核心。设计用于处理序列数据 (如时间步、单词序列)。神经元不仅接收当前时间步的输入,还接收前一个时间步自身的输出(隐藏状态),具有记忆功能,能捕捉序列中的时间依赖关系。
-
结构变体:
- 简单RNN (RNN): 基础循环单元,易受梯度消失/爆炸问题影响。
- 长短期记忆网络 (LSTM): 引入"门"机制(输入门、遗忘门、输出门),有效解决长序列依赖问题。
- 门控循环单元 (GRU): LSTM的简化版,合并了部分门,计算效率更高。
-
应用场景: 时间序列预测(股票、天气)、自然语言处理(文本生成、机器翻译、情感分析)、语音识别。
-
PyTorch 示例:
pythonimport torch.nn as nn # 定义一个LSTM层: 输入维度128, 隐藏状态维度64, 堆叠2层, batch维度为第一维(batch_first=True) lstm_layer = nn.LSTM(input_size=128, hidden_size=64, num_layers=2, batch_first=True)
-
-
批归一化层 (Batch Normalization Layer)
-
作用: 对每一层的输入进行归一化 处理(使其均值接近0,标准差接近1),然后进行缩放和偏移。加速训练收敛 ,减少对参数初始化的依赖,提高模型稳定性和泛化能力,并允许使用更高的学习率。
-
应用场景: 几乎应用于所有类型的深度神经网络,尤其是在深层网络中效果显著。
-
PyTorch 示例:
pythonimport torch.nn as nn # 定义一个2D BatchNorm层: 对具有16个通道的特征图进行归一化 bn_layer = nn.BatchNorm2d(num_features=16)
-
-
Dropout 层
-
作用: 一种强大的正则化 技术。在训练过程中,随机丢弃 (暂时置零)一部分神经元的输出(通常按概率p,如0.5)。迫使网络不依赖于少数特定的神经元,防止过拟合 ,提高模型的鲁棒性。在测试或推理阶段,所有神经元都参与计算,但输出值需要乘以
(1-p)
进行缩放(在PyTorch中,nn.Dropout
层在训练时应用dropout,在eval()
模式下自动关闭并缩放)。 -
应用场景: 广泛应用于各种网络结构,尤其在全连接层之后。
-
PyTorch 示例:
pythonimport torch.nn as nn # 定义一个Dropout层: 随机丢弃神经元的概率为0.5 dropout_layer = nn.Dropout(p=0.5)
-
-
注意力层 (Attention Layer)
-
作用: 一种机制,使模型在处理信息(尤其是序列或集合)时,能够动态地关注与当前任务最相关的部分,忽略不重要的部分。显著提升模型(特别是RNN/Transformer)在理解上下文和长距离依赖关系上的能力。
-
结构: 核心是计算输入元素(如序列中每个单词)的重要性权重(Attention Score) ,然后对输入进行加权求和,生成一个浓缩了关键信息的上下文向量。
-
应用场景: 自然语言处理(机器翻译、文本摘要、问答系统)、计算机视觉(图像描述生成)。
-
PyTorch 概念示例:
pythonimport torch import torch.nn as nn import torch.nn.functional as F class SimpleAttention(nn.Module): def __init__(self, hidden_size): super(SimpleAttention, self).__init__() self.attn = nn.Linear(hidden_size, hidden_size) # 学习权重参数 self.v = nn.Parameter(torch.randn(hidden_size)) # 可学习的向量 def forward(self, hidden, encoder_outputs): # hidden: 当前解码器状态 (batch_size, hidden_size) # encoder_outputs: 编码器所有时间步的输出 (batch_size, seq_len, hidden_size) energy = torch.tanh(self.attn(encoder_outputs)) # (batch_size, seq_len, hidden_size) energy = energy @ self.v # (batch_size, seq_len) 计算未归一化的注意力分数 attn_weights = F.softmax(energy, dim=1) # (batch_size, seq_len) 归一化权重 context = torch.sum(attn_weights.unsqueeze(2) * encoder_outputs, dim=1) # (batch_size, hidden_size) 加权求和 return context, attn_weights
-
-
Transformer 层
-
作用: 革命性的架构,完全基于自注意力机制 (Self-Attention) 和 多头注意力 (Multi-Head Attention) ,摒弃了RNN的循环结构。能够并行处理整个序列,极大提高训练效率,并擅长捕捉长距离依赖关系。已成为NLP领域的基石模型(如BERT, GPT),并扩展到CV(如Vision Transformer)。
-
核心结构 (以Encoder为例):
- 多头自注意力 (Multi-Head Self-Attention): 允许模型同时关注输入序列不同位置的不同表示子空间。
- 前馈神经网络 (Position-wise Feed-Forward Network): 对每个位置独立应用相同的全连接层进行变换。
- 残差连接 (Residual Connection) 与 层归一化 (Layer Normalization): 围绕子层(注意力、前馈)添加,缓解梯度消失,稳定训练。
-
应用场景: 自然语言处理(机器翻译、文本生成、问答系统、文本分类)、计算机视觉(图像分类、目标检测)。
-
PyTorch 概念示例 (简化版MultiHeadAttention):
pythonimport torch import torch.nn as nn import torch.nn.functional as F class MultiHeadAttention(nn.Module): def __init__(self, embed_size, heads): super(MultiHeadAttention, self).__init__() self.embed_size = embed_size self.heads = heads self.head_dim = embed_size // heads # 确保embed_size能被heads整除 assert self.head_dim * heads == embed_size, "Embed size needs to be divisible by heads" # 线性变换层 (投影到Q, K, V空间) self.values = nn.Linear(self.head_dim, self.head_dim, bias=False) self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False) self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False) # 合并多头输出的线性层 self.fc_out = nn.Linear(heads * self.head_dim, embed_size) def forward(self, values, keys, query): # 获取batch大小 N = query.shape[0] # 获取序列长度 value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1] # 分割嵌入维度到多个头 (Split the embedding into self.heads different pieces) values = values.reshape(N, value_len, self.heads, self.head_dim) keys = keys.reshape(N, key_len, self.heads, self.head_dim) queries = query.reshape(N, query_len, self.heads, self.head_dim) # 线性投影到Q, K, V空间 values = self.values(values) keys = self.keys(keys) queries = self.queries(queries) # 计算注意力能量 (energy) 使用einsum高效计算矩阵乘法 # Q的形状: (N, query_len, heads, head_dim) -> 看作 (nqhd) # K的形状: (N, key_len, heads, head_dim) -> 看作 (nkhd) # 结果: (N, heads, query_len, key_len) -> 看作 (nhqk) energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys]) # 缩放点积注意力 (Scale dot-product attention) energy = energy / (self.embed_size ** (1 / 2)) # 除以sqrt(d_k) # 计算注意力权重 (Softmax over the key dimension) attention = torch.softmax(energy, dim=3) # dim=3 is key_len dimension # 应用注意力权重到Value上 # attention: (N, heads, query_len, key_len) -> (nhql) # values: (N, value_len, heads, head_dim) -> (nlhd) [value_len usually equals key_len] # 结果: (N, query_len, heads, head_dim) -> (nqhd) out = torch.einsum("nhql,nlhd->nqhd", [attention, values]) # 合并多头输出: 将最后两个维度(heads * head_dim)展平 -> (N, query_len, heads * head_dim) out = out.reshape(N, query_len, self.heads * self.head_dim) # 通过最终的线性层投影回原始嵌入维度 out = self.fc_out(out) return out
- Transformer 通常由多个 Encoder Block 和 Decoder Block 堆叠而成。每个 Encoder Block 包含一个多头自注意力层和一个前馈层(均带残差连接和层归一化)。Decoder Block 包含一个带掩码的多头自注意力层(防止看到未来信息)、一个编码器-解码器注意力层(关注编码器输出)和一个前馈层。
-
-
自定义层
- 除了标准层,可以根据特定任务需求设计自定义层,例如在全连接层中使用特殊激活函数,或在卷积层中使用特定形状的卷积核。
3. 防止模型过拟合:提升泛化能力
过拟合是指模型在训练数据上表现优异,但在未见过的新数据(验证集/测试集)上表现显著下降。防止过拟合是深度学习的核心挑战之一。常用策略包括:
-
正则化 (Regularization):
-
L1 正则化: 在损失函数中添加权重的绝对值之和
λ * Σ|w|
。鼓励模型产生稀疏权重(部分w为0),自动进行特征选择。 -
L2 正则化 (权重衰减): 在损失函数中添加权重的平方和
λ * Σw²
。惩罚大的权重值 ,鼓励模型使用更小的权重,降低模型复杂度。PyTorch优化器通常直接通过weight_decay
参数实现。pythonoptimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01) # L2正则化强度0.01
-
-
Dropout: (如前所述) 训练时随机丢弃神经元,强制网络学习更鲁棒的特征表示。
-
批归一化 (Batch Normalization): (如前所述) 通过稳定层输入的分布来加速训练并间接提升泛化能力。
-
数据增强 (Data Augmentation): 在训练过程中,对输入数据应用随机但合理的变换 (如图像的旋转、翻转、裁剪、缩放、颜色抖动;文本的回译、同义词替换等),生成"新"的训练样本。增加数据多样性,使模型学习到更本质的特征,而不是训练数据的特定细节。
pythonfrom torchvision import transforms # 图像数据增强示例 train_transform = transforms.Compose([ transforms.RandomHorizontalFlip(), # 随机水平翻转 transforms.RandomRotation(10), # 随机旋转 ±10度 transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1), # 随机颜色抖动 transforms.RandomCrop(32, padding=4), # 随机裁剪(32x32)带4像素填充 transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ])
-
早停法 (Early Stopping): 在训练过程中持续监控验证集上的性能 (如验证损失或准确率)。当验证集性能在连续若干个轮次(Patience)内不再提升(甚至开始下降)时,提前终止训练,并回滚到验证集性能最好的模型参数。有效防止在训练集上过度优化。
pythonpatience = 5 # 容忍验证损失不下降的轮次 best_val_loss = float('inf') counter = 0 for epoch in range(num_epochs): # ... 训练一个epoch ... # ... 在验证集上评估 ... val_loss = evaluate(model, val_loader, criterion) if val_loss < best_val_loss: best_val_loss = val_loss torch.save(model.state_dict(), 'best_model.pth') # 保存当前最佳模型 counter = 0 # 重置计数器 else: counter += 1 if counter >= patience: print(f'Early stopping triggered at epoch {epoch}') break # 提前停止训练 # 训练结束后,加载验证集上表现最好的模型 model.load_state_dict(torch.load('best_model.pth'))
-
减少模型复杂度: 如果模型在训练集上就难以拟合(欠拟合),可能需要增加复杂度。但如果模型过拟合,一个直接的方法是减少网络的容量:减少隐藏层的数量或减少每层神经元的数量。让模型的学习能力与任务的复杂性相匹配。
-
交叉验证 (Cross-Validation): 尤其在数据量有限时常用(如K-Fold)。将训练集分成K份,轮流用其中K-1份训练,1份验证。循环K次后取平均性能。提供更可靠的模型性能估计,并帮助选择最佳超参数。
pythonfrom sklearn.model_selection import KFold kfold = KFold(n_splits=5, shuffle=True) for fold, (train_idx, val_idx) in enumerate(kfold.split(train_data)): train_subsampler = torch.utils.data.SubsetRandomSampler(train_idx) val_subsampler = torch.utils.data.SubsetRandomSampler(val_idx) train_loader = DataLoader(train_data, batch_size=64, sampler=train_subsampler) val_loader = DataLoader(train_data, batch_size=64, sampler=val_subsampler) # 在当前的训练/验证划分上训练和评估模型 ...
-
集成学习 (Ensemble Learning): 训练多个不同的模型 (不同结构、不同初始化、不同训练数据子集),然后组合它们的预测结果(如投票、平均)。集成方法通常能显著降低预测方差,提高最终模型的泛化能力。常见方法有Bagging、Boosting、Stacking。
python# 概念示例 (模型平均) model1 = SimpleCNN() model2 = AnotherCNN() model3 = YetAnotherCNN() # 训练每个模型... # ... # 预测时取平均 outputs = (model1(input) + model2(input) + model3(input)) / 3.0
4. 损失函数、激活函数与优化器:模型的驱动力
在定义好网络结构后,还需要指定三个关键组件:
- 激活函数 (Activation Functions): 引入非线性,使神经网络能够拟合复杂函数。常见于隐藏层输出和输出层。
- 损失函数 (Loss Functions / Cost Functions): 量化模型的预测值 与真实值之间的差距。指导模型优化的方向。
- 优化器 (Optimizers): 根据损失函数计算出的梯度 ,决定如何更新模型参数以最小化损失。
常见激活函数
- ReLU (Rectified Linear Unit):
f(x) = max(0, x)
。最常用,计算高效,缓解梯度消失(正区间)。缺点:负区间梯度为0("死亡ReLU"问题)。 - Sigmoid:
f(x) = 1 / (1 + exp(-x))
。输出范围(0,1)。常用于二分类输出层。缺点:易饱和导致梯度消失,输出非零中心。 - Tanh (Hyperbolic Tangent):
f(x) = tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
。输出范围(-1,1),零中心。常用于隐藏层。缺点:同样存在饱和问题。 - Leaky ReLU:
f(x) = max(αx, x)
(α是一个小的正数,如0.01)。解决ReLU负区间"死亡"问题。 - Softmax:
f(x_i) = exp(x_i) / Σ_j exp(x_j)
。将多个神经元的输出转换为概率分布 (和为1)。专用于多分类任务 的输出层。
常见损失函数
- 均方误差 (MSE, Mean Squared Error):
(1/N) * Σ(y_true - y_pred)²
。回归任务标准损失函数。对离群点敏感。 - 交叉熵损失 (Cross-Entropy Loss):
- 二分类交叉熵 (BCE):
-(1/N) * Σ [y_true * log(y_pred) + (1-y_true) * log(1-y_pred)]
。用于二分类任务(输出层Sigmoid)。 - 多分类交叉熵 (CCE / CE):
-(1/N) * Σ Σ y_true_i * log(y_pred_i)
。用于多分类 任务(输出层Softmax)。PyTorch的nn.CrossEntropyLoss
内部已包含Softmax,输入应是未归一化的分数(logits),标签是类别索引。
- 二分类交叉熵 (BCE):
- 二元交叉熵 (带Logits, BCEWithLogitsLoss): PyTorch提供。结合了Sigmoid + BCE Loss,数值计算更稳定。用于二分类(输入是logits)。
- Hinge Loss (合页损失):
max(0, 1 - y_true * y_pred)
。常用于支持向量机 (SVM) 和某些分类任务。 - Smooth L1 Loss: 对离群点比MSE更鲁棒。常用于目标检测中的边界框回归。
常见优化器
- SGD (Stochastic Gradient Descent):
w = w - lr * ∇w
。最基础。可添加动量 (Momentum) 加速收敛并抑制振荡:v = momentum * v - lr * ∇w; w = w + v
。 - Adam (Adaptive Moment Estimation): 结合了动量 和自适应学习率 (类似RMSprop)。计算每个参数的自适应学习率。最常用 ,通常收敛快且鲁棒性好。
optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
- RMSprop: 通过除以梯度的平方的指数移动平均值 来调整每个参数的学习率。适合处理非平稳目标。
optim.RMSprop(model.parameters(), lr=0.01, alpha=0.99)
- Adagrad: 为每个参数累积历史梯度的平方,据此调整学习率(历史梯度大的参数学习率小)。适合稀疏数据(如NLP),但学习率会单调下降至过小。
optim.Adagrad(model.parameters(), lr=0.01)
- Adadelta: Adagrad的改进,限制历史梯度累计窗口(使用滑动平均),避免学习率过早衰减。
optim.Adadelta(model.parameters(), lr=1.0, rho=0.9)
选择指南:
- 损失函数: 回归任务选MSE/SmoothL1;二分类选BCE/BCEWithLogitsLoss;多分类选CrossEntropyLoss。
- 激活函数: 隐藏层首选ReLU或其变体(Leaky ReLU);二分类输出层用Sigmoid;多分类输出层用Softmax(或让CrossEntropyLoss内部处理)。
- 优化器: Adam通常是很好的默认选择。对某些任务或追求极致性能时,可尝试带动量的SGD或RMSprop。
三、 Python深度学习生态系统
Python拥有丰富的库支持深度学习研究和开发:
- 核心框架:
- PyTorch: 由Facebook开发。动态计算图 (Eager Execution),灵活易调试,研究首选。API设计直观。
pip install torch torchvision torchaudio
- TensorFlow: 由Google开发。支持静态图 (Graph Mode)和动态图 (Eager Mode)。生产部署工具链成熟(TF Serving, TFLite)。高级API Keras 已紧密集成。
pip install tensorflow
- JAX: 由Google开发。基于函数式编程和自动微分。强调可组合函数变换(grad, jit, vmap, pmap)。高性能(尤其适合科学计算),研究前沿。
- PyTorch: 由Facebook开发。动态计算图 (Eager Execution),灵活易调试,研究首选。API设计直观。
- 高层API/封装:
- Keras: 最初独立,现为TensorFlow官方高级API。极简设计,快速原型开发。也可作为独立库使用(
pip install keras
)。
- Keras: 最初独立,现为TensorFlow官方高级API。极简设计,快速原型开发。也可作为独立库使用(
- 数据处理与科学计算:
- NumPy: 科学计算基石,提供高效多维数组操作。
pip install numpy
- Pandas: 数据处理和分析利器,核心数据结构
DataFrame
。pip install pandas
- SciPy: 基于NumPy,提供科学计算工具(优化、积分、插值、信号处理等)。
pip install scipy
- NumPy: 科学计算基石,提供高效多维数组操作。
- 数据可视化:
- Matplotlib: 最基础的2D绘图库,高度可定制。
pip install matplotlib
- Seaborn: 基于Matplotlib的高级统计绘图库,默认样式美观,API简洁。
pip install seaborn
- Plotly / Bokeh: 交互式可视化库,适合创建Web交互图表。
- Matplotlib: 最基础的2D绘图库,高度可定制。
- 工具库:
- Scikit-learn: 经典机器学习库(分类、回归、聚类、降维、模型选择等)。包含大量实用工具(数据预处理、评估指标)。
pip install scikit-learn
- OpenCV (cv2): 计算机视觉基础库(图像/视频处理、特征提取、对象检测等)。
pip install opencv-python
- NLTK / spaCy: 自然语言处理工具包。
- Scikit-learn: 经典机器学习库(分类、回归、聚类、降维、模型选择等)。包含大量实用工具(数据预处理、评估指标)。
四、 PyTorch实战:从搭建到训练
PyTorch是一个基于Python的开源深度学习框架,以其动态计算图 (定义即执行,易于调试)和直观的面向对象设计而深受研究人员喜爱。
PyTorch核心组件
-
张量 (Tensor): 基础数据结构,类似NumPy数组,但支持GPU加速和自动求导。
x = torch.tensor([1.0, 2.0], requires_grad=True)
-
自动求导 (Autograd): 引擎,自动计算张量的梯度(
backward()
)。y = x.sum(); y.backward(); print(x.grad)
-
神经网络模块 (
nn.Module
): 所有自定义模型的基类 。必须实现__init__
(定义层和参数)和forward
(定义前向传播逻辑)。负责管理参数、子模块、设备转移等。不重写forward
方法是不可行的!pythonimport torch.nn as nn class MyModel(nn.Module): def __init__(self): super().__init__() self.layer1 = nn.Linear(10, 20) # 定义层/参数 self.layer2 = nn.Linear(20, 1) def forward(self, x): # 必须重写: 定义数据如何流经网络 x = torch.relu(self.layer1(x)) x = self.layer2(x) return x model = MyModel()
-
优化器 (
optim
): 管理参数更新。optimizer = optim.Adam(model.parameters(), lr=0.001)
-
数据加载 (
Dataset
&DataLoader
): 高效加载和批处理数据。Dataset
: 抽象类,需实现__len__
和__getitem__
。DataLoader
: 包装Dataset
,提供迭代器、批处理、打乱、多进程加载。
-
损失函数 (
nn
): 如前所述,nn.MSELoss()
,nn.CrossEntropyLoss()
等。
PyTorch模型训练全流程 (以图像分类为例)
-
准备数据
pythonimport torch import torchvision import torchvision.transforms as transforms # 1. 定义数据预处理/增强 transform_train = transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.RandomCrop(32, padding=4), transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), # CIFAR10均值和标准差 ]) transform_test = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) # 2. 加载数据集 train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train) test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test) # 3. 创建数据加载器 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=2) test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=100, shuffle=False, num_workers=2)
-
定义模型
pythonimport torch.nn as nn import torch.nn.functional as F class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() self.conv1 = nn.Conv2d(3, 32, 3, padding=1) # 输入3通道(RGB), 输出32特征图, 3x3卷积核, padding=1保持尺寸 self.conv2 = nn.Conv2d(32, 64, 3, padding=1) self.pool = nn.MaxPool2d(2, 2) # 2x2池化, 步长2 (尺寸减半) self.fc1 = nn.Linear(64 * 8 * 8, 512) # CIFAR10经过两次池化: 32x32 -> 16x16 -> 8x8 self.fc2 = nn.Linear(512, 10) # 输出10类 (CIFAR10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) # Conv1 -> ReLU -> Pool x = self.pool(F.relu(self.conv2(x))) # Conv2 -> ReLU -> Pool x = x.view(-1, 64 * 8 * 8) # 展平: -1表示自动计算batch_size维度, 64*8*8=4096 x = F.relu(self.fc1(x)) # FC1 -> ReLU x = self.fc2(x) # FC2 (输出层) return x model = SimpleCNN() device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model.to(device) # 将模型移动到GPU (如果可用)
-
定义损失函数和优化器
pythonimport torch.optim as optim criterion = nn.CrossEntropyLoss() # 多分类交叉熵损失 optimizer = optim.Adam(model.parameters(), lr=0.001)
-
训练循环
pythonnum_epochs = 20 for epoch in range(num_epochs): model.train() # 设置为训练模式 (启用Dropout/BatchNorm训练行为) running_loss = 0.0 correct = 0 total = 0 for i, (inputs, labels) in enumerate(train_loader, 0): inputs, labels = inputs.to(device), labels.to(device) # 移动数据到设备 # 梯度清零 (重要!) optimizer.zero_grad() # 前向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播 + 参数更新 loss.backward() optimizer.step() # 统计训练损失和准确率 running_loss += loss.item() _, predicted = outputs.max(1) total += labels.size(0) correct += predicted.eq(labels).sum().item() # 定期打印训练状态 if i % 100 == 99: # 每100个batch打印一次 print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], ' f'Loss: {running_loss / 100:.4f}, Acc: {100. * correct / total:.2f}%') running_loss = 0.0 # 可选: 每个epoch结束后在验证集/测试集上评估一次 model.eval() # 设置为评估模式 (关闭Dropout, 固定BatchNorm统计量) test_loss = 0 test_correct = 0 test_total = 0 with torch.no_grad(): # 禁用梯度计算,节省内存和计算 for inputs, labels in test_loader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) loss = criterion(outputs, labels) test_loss += loss.item() _, predicted = outputs.max(1) test_total += labels.size(0) test_correct += predicted.eq(labels).sum().item() print(f'Epoch [{epoch+1}/{num_epochs}] Test Loss: {test_loss / len(test_loader):.4f}, ' f'Test Acc: {100. * test_correct / test_total:.2f}%') print('Finished Training')
-
评估模型
pythonmodel.eval() # 确保在评估模式 correct = 0 total = 0 with torch.no_grad(): for (inputs, labels) in test_loader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) _, predicted = torch.max(outputs.data, 1) # 获取预测类别 (dim=1上最大值的索引) total += labels.size(0) correct += (predicted == labels).sum().item() print(f'Final Test Accuracy: {100 * correct / total:.2f}%')
-
保存和加载模型
python# 保存模型状态字典 (推荐) torch.save(model.state_dict(), 'cifar10_cnn_model.pth') # 加载模型 (需要先实例化相同结构的模型) loaded_model = SimpleCNN() loaded_model.load_state_dict(torch.load('cifar10_cnn_model.pth')) loaded_model.to(device) loaded_model.eval() # 加载后用于预测前务必设置为eval模式
五、 常见神经网络模型类型
不同的任务和数据特性需要不同的网络结构:
- 卷积神经网络 (CNN): 图像处理王者 。核心组件:卷积层(提取局部特征)、池化层(下采样)、全连接层(分类/回归)。应用:图像分类、目标检测、语义分割、人脸识别。 (见上文的
SimpleCNN
示例) - 循环神经网络 (RNN) / 长短时记忆网络 (LSTM) / 门控循环单元 (GRU): 序列数据专家 。具有记忆功能,能处理变长序列,捕捉时间依赖。应用:自然语言处理(机器翻译、文本生成、情感分析)、时间序列预测(股票、天气)、语音识别。 (见上文RNN/LSTM层描述及示例)
- Transformer: 序列建模新范式 。完全基于自注意力机制 ,并行处理能力强,擅长捕捉长距离依赖。已成为NLP事实标准(BERT, GPT, T5),并进军CV(ViT, DETR)。核心:多头注意力、位置编码、前馈网络、残差连接、层归一化。应用:机器翻译、文本摘要、问答系统、图像分类、目标检测。 (见上文Transformer层描述及示例)
- 生成对抗网络 (GAN): 生成模型代表 。由生成器 (Generator) 和判别器 (Discriminator) 对抗训练。生成器学习生成逼真数据,判别器学习区分真实数据和生成数据。应用:图像生成、图像超分辨率、风格迁移、数据增强。 (见上文GAN示例)
- 自编码器 (Autoencoder): 无监督特征学习/降维 。由编码器 (Encoder) 将输入压缩为低维潜在表示 (Latent Representation / Code) ,解码器 (Decoder) 从潜在表示重建输入。目标是最小化重建误差。应用:降维、异常检测、图像去噪、特征提取。 (见上文Autoencoder示例)
- 图神经网络 (GNN): 图结构数据建模 。将神经网络应用于图数据(节点、边)。核心思想是聚合邻居节点信息来更新节点表示。应用:社交网络分析、推荐系统、分子性质预测、知识图谱。 (见上文GNN示例)
结语
深度学习是一个庞大且快速发展的领域。这篇博客梳理了我近期学习的核心概念:从理解深度学习本质(特征提取与参数优化)、模型构建的关键要素(数据、层、防过拟合、损失函数、优化器)、必备的Python工具,到使用PyTorch进行实战(数据加载、模型定义、训练循环、评估保存)。最后概述了主流的神经网络架构及其适用场景。
学习过程中,动手实践(敲代码、调模型)至关重要。虽然内容繁多,难免懵懂,但通过不断梳理、实践和总结,理解会逐步深入。这篇博客是我学习路上的一个小小里程碑,希望能对同样入门的朋友有所帮助。文中难免有理解不深或表述不当之处,恳请各位读者不吝指正!