模型文件

  1. 模型文件,也叫模型权重,里面大部分空间存放的是模型参数 - 即权重(Weights)和偏置(Biases)
  2. 还有其它信息,如优化器状态元数据
  3. 文件格式
    • 使用 PyTorch,后缀为 .pth
    • 使用 TensorFlow 或者 Hugging Face Transformers,后缀为 .bin
  4. 在模型预训练后,可以保存模型,在生产环境,不建议保存模型架构
    • Python 版本模型定义的代码紧密相关,可能存在兼容性问题

模型权重 - 推荐

1
torch.save(model.state_dict(), 'model_weights.pth')

模型权重 + 模型架构 - 可能存在兼容性问题

1
torch.save(model, model_path)

权重 + 偏置

  1. 权重 - 最重要的参数之一
    • 前向传播过程中,输入会与权重相乘,这是神经网络学习特征和模式的基本方式
    • 权重决定了输入如何影响输出
  2. 偏置 - 调整输出
    • 允许模型输出在没有输入或者所有输入都为 0 的时候,调整到某个基线值
  3. $y=kx+b$
    • $k$ 为权重,$b$ 为偏置
    • 神经网络中,权重 $k$ 决定了每个输入特征对于输出重要性影响力
    • 偏置 $b$ 是个常数项,提供除了输入特征之外的额外输入
      • 允许模型输出可以在没有任何输入或者所有输入都为 0 的时候,调整到某个基线阈值
  4. 复杂的神经网络中,每个神经元都有权重偏置
    • 前一层接收多个输入信号,对这些输入信号加权求和加上偏置
    • 然后通过一个非线性激活函数tanh or ReLU)来生成输出信号 - 传递到下一层
    • 每一层的权重和偏置都是模型需要学习的参数,根据训练数据进行调整,以最小化模型的预测误差

模型可视化

Netron - 整体结构

6 层 Transformer Decoder-only 架构

image-20240827191733137

Embedding

image-20240827192038385

  1. weight(168283×512)
    • 代表 168283×512 的矩阵,每一行对应一个特定的词向量
    • 对于词汇表中一个或者标记,该矩阵提供了一个 512 维的嵌入向量
  2. tensor: float32[168283,512]
    • 表明这是一个 FP32 精度的变量,168283 表明训练时使用了 168283 个词汇

TransformerDecoderLayer

具体的实现类 - torch.nn.modules.transformer.TransformerDecoderLayer

image-20240827193020818

包含组件

1
2
3
4
5
6
7
8
9
10
11
torch.nn.modules.activation.MultiheadAttention
torch.nn.modules.activation.MultiheadAttention
torch.nn.modules.linear.Linear
torch.nn.modules.dropout.Dropout
torch.nn.modules.linear.Linear
torch.nn.modules.normalization.LayerNorm
torch.nn.modules.normalization.LayerNorm
torch.nn.modules.normalization.LayerNorm
torch.nn.modules.dropout.Dropout
torch.nn.modules.dropout.Dropout
torch.nn.modules.dropout.Dropout

torchviz - 具体节点

1
2
3
4
x = torch.randint(10000, (50,))  # 假设一个序列长度为10的输入
y = model(x)
dot = torchviz.make_dot(y.mean(), params=dict(model.named_parameters()), show_attrs=True, show_saved=True)
dot.render(filename="net", format='png')

整个网络结构的顺序图

image-20240827200018832

训练

  1. 模型的训练过程就是不断调整权重的过程
  2. 调整权重的依据就是根据损失函数计算损失,通过反向传播不断调整权重使得损失最小
  3. 达到理想损失值后,把权重记录下来保存

推理

  1. 数据到达节点(神经元)后,先从输入层隐藏层,再从隐藏层到输出层
  2. 每一层都执行 $y_1=k_1x_1+b_1$,然后应用非线性激活函数,比如 $x_2=ReLU(y_1)$,最后将 $x_2$ 继续传递下一层
  3. 下一层的权重 $k_2$ 和偏置 $b_2$ 是已知的,继续计算得到 $y_2$​
  4. 基本都是张量相乘,而不是简单的整数小数相乘

机器学习框架(PyTorch)可以根据描述文件,将模型重构出来,进行训练推理

模型容量

存储大小

755M

总参数量

vocab_size × embed_size + embed_size + (4 × embed_size × embed_size + 2 × (embed_size × hidden_dim)) × 层数 + vocab_size × embed_size

vocab_size × 512 + 512 + (4 × 512 × 512 + 2 × (512 × 2048)) × 6 + vocab_size × 512

vocab_size = 168283
168283 × 512 + 512 + (4 × 512 × 512 + 2 × (512 × 2048)) × 6 + 168283 × 512 = 191,196,672 = 1.9 亿

  1. 模型的精度float32,即每个参数需要 4 字节的存储空间
  2. 纯参数方面大约需要 729M 的空间(191,196,672×4/1024/1024),占比 96.5%,剩余 26M 的空间可能存放的是模型结构元数据

Embedding 层

Embedding 层在整个模型中的作用非常大,占比 40%

  1. 权重是 tensor: float32[168283,512]
  2. 在 Embedding 层参数量为 168283×512 = 86,160,896,存储≈ 328M
    • 参数占比 = 86,160,896 / 191,196,672 ≈ 0.45
    • 存储占比 = 328 / 755 ≈ 0.43

模型参数

0512aee8bd58e69d07a6c51943cd4f73.png

  1. 具有 50 个参数的矩阵,每个参数表示词向量特定维度上的权重特征
  2. 每一行表示某个词在 10 个不同的特征维度上的数值表示
  3. 假设 Embedding 层是可训练
    • 模型训练的过程中,会根据损失计算,反向传播更新某个参数
    • 使得模型可以更好地表示某个词,来达到训练的目的
  4. 在最终的推理过程中,词向量会被传播下去,作为下一层神经网络的输入,参与到后续的计算过程中

小结

类比 - 通过 Java 字节码文件反推 Java 编码过程

  1. 模型里存放的是各个层权重偏置,类似于 $y=kx+b$ 里面的 $k$ 和 $b$
  2. 机器学习框架(PyTorch)可以识别模型文件,并且把模型结构重构出来进行训练推理
  3. 模型训练过程 - 不断前向传播损失计算反向传播参数更新的过程
  4. 模型推理过程 - 根据训练好的参数,进行前向传播的过程
  5. 模型可视化工具 - Netron + torchviz