深度学习

最近学习了深度学习,感觉内容非常丰富,目前还在消化吸收中。写这篇博客主要是为了梳理我这几天所学,记录学习足迹,也欢迎各位读者指出不足之处!

一、 什么是深度学习:特征提取的艺术

简单来说,深度学习是机器学习的一个分支,其核心在于如何让机器自动地从数据中学习和提取有效的特征,进而完成复杂的任务(如分类、识别、预测等)。

举个例子:为了实现为每个用户推送最合适的抖音视频内容,我们可以构建一个神经网络模型。这个模型的输入是用户历史观看行为数据(数据中蕴含海量特征),输出则是模型学习到的、代表用户对不同内容特征偏好程度的权重(例如,特征A占30%,特征B占50%...)。后续推送就可以侧重这些高权重特征相关的视频。

那么,这个模型是如何构建和工作的呢?

  1. 模型基础: 类似于函数 y = w * x + b。数据x输入模型,经过一系列计算得到输出y
  2. 参数学习: w(权重参数) 决定了输入特征x对结果y的影响大小(w越大,该特征越重要);b(偏置项) 是模型的偏移量。
  3. 训练过程: 如何让模型预测更准确?需要输入大量的训练数据进行训练
    • 初始化: 首先构建模型的基本框架(网络结构),其中的wb初始值通常随机生成。
    • 前向传播: 将训练数据输入模型,数据流经网络各层进行计算,最终得到预测输出y_pred
    • 计算损失: 将模型的预测输出y_pred与真实的标签y_true进行比较,使用损失函数 (如均方误差MSE、交叉熵CrossEntropy)计算它们之间的差异(损失值loss)。
    • 反向传播: 核心步骤!利用链式法则,计算损失函数loss相对于模型每个参数(w, b)的梯度 (偏导数 ∂loss/∂w, ∂loss/∂b)。梯度指示了参数需要调整的方向和幅度(减少loss的方向)。
    • 参数更新: 使用优化器 (如SGD, Adam)根据计算出的梯度更新模型的wb值(例如:w = w - learning_rate * ∂loss/∂w)。
  4. 迭代优化: 重复执行前向传播->计算损失->反向传播->更新参数这个过程数千次甚至上万次(称为"迭代"或"轮次"),模型参数(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)。

常见的隐藏层类型:

  1. 全连接层 (Fully Connected Layer / Dense Layer)

    • 作用: 对输入数据进行线性变换 (y = w*x + b) 后接非线性激活函数(如ReLU、Sigmoid、Tanh),提取更高级别的特征。是网络中最基础的层类型。

    • 结构: 每个神经元的输出是前一层所有神经元输入的加权和 + 偏置项,再通过激活函数。

    • 应用场景: 处理一维特征向量(如图像分类任务中卷积层提取特征后的向量、自然语言处理中的词嵌入向量)。

    • PyTorch 示例:

      python 复制代码
      import torch.nn as nn
      fc_layer = nn.Linear(in_features=128, out_features=64)  # 输入128维,输出64维
  2. 卷积层 (Convolutional Layer)

    • 作用: 卷积神经网络(CNN)的核心。使用卷积核(滤波器) 在输入数据(通常是图像)上滑动,提取局部空间特征(如边缘、纹理)。模拟了人类视觉系统逐层提取特征的过程。卷积核的数量决定了输出特征图的通道数(深度)。

    • 结构: 输入数据(如H x W x C的图像)与卷积核进行卷积运算,生成特征图(Feature Map)。每个卷积核学习提取一种特定的局部特征模式。

    • 应用场景: 图像处理、计算机视觉(图像分类、目标检测、语义分割等)。

    • PyTorch 示例与参数详解:

      python 复制代码
      import 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可保持输入输出宽高不变。
  3. 池化层 (Pooling Layer)

    • 作用: 通常跟在卷积层后。对局部区域进行下采样 ,降低特征图的空间分辨率(宽度和高度),减少计算量和参数数量 ,同时保留重要特征(如最大池化保留最显著特征),并赋予模型一定的平移不变性

    • 结构:

      • 最大池化 (Max Pooling): 取局部区域内的最大值。
      • 平均池化 (Average Pooling): 取局部区域内的平均值。
    • 应用场景: 图像处理、计算机视觉任务。

    • PyTorch 示例:

      python 复制代码
      import torch.nn as nn
      # 定义一个最大池化层: 池化窗口2x2, 滑动步长2 (通常步长等于窗口大小,实现减半下采样)
      max_pool_layer = nn.MaxPool2d(kernel_size=2, stride=2)
  4. 循环层 (Recurrent Layer)

    • 作用: 循环神经网络(RNN)的核心。设计用于处理序列数据 (如时间步、单词序列)。神经元不仅接收当前时间步的输入,还接收前一个时间步自身的输出(隐藏状态),具有记忆功能,能捕捉序列中的时间依赖关系。

    • 结构变体:

      • 简单RNN (RNN): 基础循环单元,易受梯度消失/爆炸问题影响。
      • 长短期记忆网络 (LSTM): 引入"门"机制(输入门、遗忘门、输出门),有效解决长序列依赖问题。
      • 门控循环单元 (GRU): LSTM的简化版,合并了部分门,计算效率更高。
    • 应用场景: 时间序列预测(股票、天气)、自然语言处理(文本生成、机器翻译、情感分析)、语音识别。

    • PyTorch 示例:

      python 复制代码
      import 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)
  5. 批归一化层 (Batch Normalization Layer)

    • 作用: 对每一层的输入进行归一化 处理(使其均值接近0,标准差接近1),然后进行缩放和偏移。加速训练收敛 ,减少对参数初始化的依赖,提高模型稳定性和泛化能力,并允许使用更高的学习率。

    • 应用场景: 几乎应用于所有类型的深度神经网络,尤其是在深层网络中效果显著。

    • PyTorch 示例:

      python 复制代码
      import torch.nn as nn
      # 定义一个2D BatchNorm层: 对具有16个通道的特征图进行归一化
      bn_layer = nn.BatchNorm2d(num_features=16)
  6. Dropout 层

    • 作用: 一种强大的正则化 技术。在训练过程中,随机丢弃 (暂时置零)一部分神经元的输出(通常按概率p,如0.5)。迫使网络不依赖于少数特定的神经元,防止过拟合 ,提高模型的鲁棒性。在测试或推理阶段,所有神经元都参与计算,但输出值需要乘以 (1-p) 进行缩放(在PyTorch中,nn.Dropout层在训练时应用dropout,在eval()模式下自动关闭并缩放)。

    • 应用场景: 广泛应用于各种网络结构,尤其在全连接层之后。

    • PyTorch 示例:

      python 复制代码
      import torch.nn as nn
      # 定义一个Dropout层: 随机丢弃神经元的概率为0.5
      dropout_layer = nn.Dropout(p=0.5)
  7. 注意力层 (Attention Layer)

    • 作用: 一种机制,使模型在处理信息(尤其是序列或集合)时,能够动态地关注与当前任务最相关的部分,忽略不重要的部分。显著提升模型(特别是RNN/Transformer)在理解上下文和长距离依赖关系上的能力。

    • 结构: 核心是计算输入元素(如序列中每个单词)的重要性权重(Attention Score) ,然后对输入进行加权求和,生成一个浓缩了关键信息的上下文向量

    • 应用场景: 自然语言处理(机器翻译、文本摘要、问答系统)、计算机视觉(图像描述生成)。

    • PyTorch 概念示例:

      python 复制代码
      import 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
  8. 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):

      python 复制代码
      import 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 BlockDecoder Block 堆叠而成。每个 Encoder Block 包含一个多头自注意力层和一个前馈层(均带残差连接和层归一化)。Decoder Block 包含一个带掩码的多头自注意力层(防止看到未来信息)、一个编码器-解码器注意力层(关注编码器输出)和一个前馈层。
  9. 自定义层

    • 除了标准层,可以根据特定任务需求设计自定义层,例如在全连接层中使用特殊激活函数,或在卷积层中使用特定形状的卷积核。

3. 防止模型过拟合:提升泛化能力

过拟合是指模型在训练数据上表现优异,但在未见过的新数据(验证集/测试集)上表现显著下降。防止过拟合是深度学习的核心挑战之一。常用策略包括:

  1. 正则化 (Regularization):

    • L1 正则化: 在损失函数中添加权重的绝对值之和 λ * Σ|w|。鼓励模型产生稀疏权重(部分w为0),自动进行特征选择。

    • L2 正则化 (权重衰减): 在损失函数中添加权重的平方和 λ * Σw²惩罚大的权重值 ,鼓励模型使用更小的权重,降低模型复杂度。PyTorch优化器通常直接通过 weight_decay 参数实现。

      python 复制代码
      optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01)  # L2正则化强度0.01
  2. Dropout: (如前所述) 训练时随机丢弃神经元,强制网络学习更鲁棒的特征表示。

  3. 批归一化 (Batch Normalization): (如前所述) 通过稳定层输入的分布来加速训练并间接提升泛化能力。

  4. 数据增强 (Data Augmentation): 在训练过程中,对输入数据应用随机但合理的变换 (如图像的旋转、翻转、裁剪、缩放、颜色抖动;文本的回译、同义词替换等),生成"新"的训练样本。增加数据多样性,使模型学习到更本质的特征,而不是训练数据的特定细节。

    python 复制代码
    from 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))
    ])
  5. 早停法 (Early Stopping): 在训练过程中持续监控验证集上的性能 (如验证损失或准确率)。当验证集性能在连续若干个轮次(Patience)内不再提升(甚至开始下降)时,提前终止训练,并回滚到验证集性能最好的模型参数。有效防止在训练集上过度优化。

    python 复制代码
    patience = 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'))
  6. 减少模型复杂度: 如果模型在训练集上就难以拟合(欠拟合),可能需要增加复杂度。但如果模型过拟合,一个直接的方法是减少网络的容量:减少隐藏层的数量或减少每层神经元的数量。让模型的学习能力与任务的复杂性相匹配。

  7. 交叉验证 (Cross-Validation): 尤其在数据量有限时常用(如K-Fold)。将训练集分成K份,轮流用其中K-1份训练,1份验证。循环K次后取平均性能。提供更可靠的模型性能估计,并帮助选择最佳超参数。

    python 复制代码
    from 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)
    
        # 在当前的训练/验证划分上训练和评估模型
        ...
  8. 集成学习 (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): 根据损失函数计算出的梯度 ,决定如何更新模型参数以最小化损失。

常见激活函数

  1. ReLU (Rectified Linear Unit): f(x) = max(0, x)。最常用,计算高效,缓解梯度消失(正区间)。缺点:负区间梯度为0("死亡ReLU"问题)。
  2. Sigmoid: f(x) = 1 / (1 + exp(-x))。输出范围(0,1)。常用于二分类输出层。缺点:易饱和导致梯度消失,输出非零中心。
  3. Tanh (Hyperbolic Tangent): f(x) = tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))。输出范围(-1,1),零中心。常用于隐藏层。缺点:同样存在饱和问题。
  4. Leaky ReLU: f(x) = max(αx, x) (α是一个小的正数,如0.01)。解决ReLU负区间"死亡"问题。
  5. Softmax: f(x_i) = exp(x_i) / Σ_j exp(x_j)。将多个神经元的输出转换为概率分布 (和为1)。专用于多分类任务输出层

常见损失函数

  1. 均方误差 (MSE, Mean Squared Error): (1/N) * Σ(y_true - y_pred)²回归任务标准损失函数。对离群点敏感。
  2. 交叉熵损失 (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),标签是类别索引。
  3. 二元交叉熵 (带Logits, BCEWithLogitsLoss): PyTorch提供。结合了Sigmoid + BCE Loss,数值计算更稳定。用于二分类(输入是logits)。
  4. Hinge Loss (合页损失): max(0, 1 - y_true * y_pred)。常用于支持向量机 (SVM) 和某些分类任务。
  5. Smooth L1 Loss: 对离群点比MSE更鲁棒。常用于目标检测中的边界框回归。

常见优化器

  1. SGD (Stochastic Gradient Descent): w = w - lr * ∇w。最基础。可添加动量 (Momentum) 加速收敛并抑制振荡:v = momentum * v - lr * ∇w; w = w + v
  2. Adam (Adaptive Moment Estimation): 结合了动量自适应学习率 (类似RMSprop)。计算每个参数的自适应学习率。最常用 ,通常收敛快且鲁棒性好。optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
  3. RMSprop: 通过除以梯度的平方的指数移动平均值 来调整每个参数的学习率。适合处理非平稳目标。optim.RMSprop(model.parameters(), lr=0.01, alpha=0.99)
  4. Adagrad: 为每个参数累积历史梯度的平方,据此调整学习率(历史梯度大的参数学习率小)。适合稀疏数据(如NLP),但学习率会单调下降至过小。optim.Adagrad(model.parameters(), lr=0.01)
  5. 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拥有丰富的库支持深度学习研究和开发:

  1. 核心框架:
    • 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)。高性能(尤其适合科学计算),研究前沿。
  2. 高层API/封装:
    • Keras: 最初独立,现为TensorFlow官方高级API。极简设计,快速原型开发。也可作为独立库使用(pip install keras)。
  3. 数据处理与科学计算:
    • NumPy: 科学计算基石,提供高效多维数组操作。pip install numpy
    • Pandas: 数据处理和分析利器,核心数据结构DataFramepip install pandas
    • SciPy: 基于NumPy,提供科学计算工具(优化、积分、插值、信号处理等)。pip install scipy
  4. 数据可视化:
    • Matplotlib: 最基础的2D绘图库,高度可定制。pip install matplotlib
    • Seaborn: 基于Matplotlib的高级统计绘图库,默认样式美观,API简洁。pip install seaborn
    • Plotly / Bokeh: 交互式可视化库,适合创建Web交互图表。
  5. 工具库:
    • Scikit-learn: 经典机器学习库(分类、回归、聚类、降维、模型选择等)。包含大量实用工具(数据预处理、评估指标)。pip install scikit-learn
    • OpenCV (cv2): 计算机视觉基础库(图像/视频处理、特征提取、对象检测等)。pip install opencv-python
    • NLTK / spaCy: 自然语言处理工具包。

四、 PyTorch实战:从搭建到训练

PyTorch是一个基于Python的开源深度学习框架,以其动态计算图 (定义即执行,易于调试)和直观的面向对象设计而深受研究人员喜爱。

PyTorch核心组件

  1. 张量 (Tensor): 基础数据结构,类似NumPy数组,但支持GPU加速和自动求导。x = torch.tensor([1.0, 2.0], requires_grad=True)

  2. 自动求导 (Autograd): 引擎,自动计算张量的梯度(backward())。y = x.sum(); y.backward(); print(x.grad)

  3. 神经网络模块 (nn.Module): 所有自定义模型的基类 。必须实现__init__(定义层和参数)和forward(定义前向传播逻辑)。负责管理参数、子模块、设备转移等。不重写forward方法是不可行的!

    python 复制代码
    import 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()
  4. 优化器 (optim): 管理参数更新。optimizer = optim.Adam(model.parameters(), lr=0.001)

  5. 数据加载 (Dataset & DataLoader): 高效加载和批处理数据。

    • Dataset: 抽象类,需实现__len____getitem__
    • DataLoader: 包装Dataset,提供迭代器、批处理、打乱、多进程加载。
  6. 损失函数 (nn): 如前所述,nn.MSELoss(), nn.CrossEntropyLoss()等。

PyTorch模型训练全流程 (以图像分类为例)

  1. 准备数据

    python 复制代码
    import 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)
  2. 定义模型

    python 复制代码
    import 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 (如果可用)
  3. 定义损失函数和优化器

    python 复制代码
    import torch.optim as optim
    
    criterion = nn.CrossEntropyLoss()  # 多分类交叉熵损失
    optimizer = optim.Adam(model.parameters(), lr=0.001)
  4. 训练循环

    python 复制代码
    num_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')
  5. 评估模型

    python 复制代码
    model.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}%')
  6. 保存和加载模型

    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模式

五、 常见神经网络模型类型

不同的任务和数据特性需要不同的网络结构:

  1. 卷积神经网络 (CNN): 图像处理王者 。核心组件:卷积层(提取局部特征)、池化层(下采样)、全连接层(分类/回归)。应用:图像分类、目标检测、语义分割、人脸识别。 (见上文的SimpleCNN示例)
  2. 循环神经网络 (RNN) / 长短时记忆网络 (LSTM) / 门控循环单元 (GRU): 序列数据专家 。具有记忆功能,能处理变长序列,捕捉时间依赖。应用:自然语言处理(机器翻译、文本生成、情感分析)、时间序列预测(股票、天气)、语音识别。 (见上文RNN/LSTM层描述及示例)
  3. Transformer: 序列建模新范式 。完全基于自注意力机制 ,并行处理能力强,擅长捕捉长距离依赖。已成为NLP事实标准(BERT, GPT, T5),并进军CV(ViT, DETR)。核心:多头注意力、位置编码、前馈网络、残差连接、层归一化。应用:机器翻译、文本摘要、问答系统、图像分类、目标检测。 (见上文Transformer层描述及示例)
  4. 生成对抗网络 (GAN): 生成模型代表 。由生成器 (Generator)判别器 (Discriminator) 对抗训练。生成器学习生成逼真数据,判别器学习区分真实数据和生成数据。应用:图像生成、图像超分辨率、风格迁移、数据增强。 (见上文GAN示例)
  5. 自编码器 (Autoencoder): 无监督特征学习/降维 。由编码器 (Encoder) 将输入压缩为低维潜在表示 (Latent Representation / Code)解码器 (Decoder) 从潜在表示重建输入。目标是最小化重建误差。应用:降维、异常检测、图像去噪、特征提取。 (见上文Autoencoder示例)
  6. 图神经网络 (GNN): 图结构数据建模 。将神经网络应用于图数据(节点、边)。核心思想是聚合邻居节点信息来更新节点表示。应用:社交网络分析、推荐系统、分子性质预测、知识图谱。 (见上文GNN示例)

结语

深度学习是一个庞大且快速发展的领域。这篇博客梳理了我近期学习的核心概念:从理解深度学习本质(特征提取与参数优化)、模型构建的关键要素(数据、层、防过拟合、损失函数、优化器)、必备的Python工具,到使用PyTorch进行实战(数据加载、模型定义、训练循环、评估保存)。最后概述了主流的神经网络架构及其适用场景。

学习过程中,动手实践(敲代码、调模型)至关重要。虽然内容繁多,难免懵懂,但通过不断梳理、实践和总结,理解会逐步深入。这篇博客是我学习路上的一个小小里程碑,希望能对同样入门的朋友有所帮助。文中难免有理解不深或表述不当之处,恳请各位读者不吝指正!

相关推荐
深小乐4 小时前
AI 周刊【2026.04.27-05.03】:Anthropic 9000亿美元估值、英伟达死磕智能体、中央重磅定调AI
人工智能
码点滴4 小时前
什么时候用 DeepSeek V4,而不是 GPT-5/Claude/Gemini?
人工智能·gpt·架构·大模型·deepseek
狐狐生风4 小时前
LangChain 向量存储:Chroma、FAISS
人工智能·python·学习·langchain·faiss·agentai
波动几何4 小时前
CDA架构代码工坊技能cda-code-lab
人工智能
舟遥遥娓飘飘4 小时前
DeepSeek V4技术变革对社会结构与职业体系的重构
人工智能
狐狐生风4 小时前
LangChain RAG 基础
人工智能·python·学习·langchain·rag·agentai
哥布林学者5 小时前
深度学习进阶(十五)通道注意力 SE
机器学习·ai
墨北小七5 小时前
使用InspireFace进行智慧楼宇门禁人脸识别的训练微调
人工智能·深度学习·神经网络
HackTorjan5 小时前
深度神经网络的反向传播与梯度优化原理
人工智能·spring boot·神经网络·机器学习·dnn
PersistJiao5 小时前
Codex、Claude Code、gstack三者的关系
人工智能