目录
- 前言
- 一、课程整体概览
- 二、训练环境:沐曦C500 + mcPyTorch
- 1. 环境组成
- 2. 上机前三项自检(必做)
- 三、数据集:Tatoeba英中平行语料
- 四、文本输入处理:分词、BPE、词表、位置编码
- 1. 原始文本到模型输入两步转换
- 2. 为什么选择BPE子词切分
- 3. 特殊符号索引坑点
- 4. 位置编码
- 五、Transformer Encoder-Decoder核心机制
- 1. Encoder与Decoder分工
- 2. 缩放点积注意力四步(本课手动实现)
- 3. 三处注意力,分清Q/K/V来源
- 4. 多头注意力
- 5. Mask组合,极易踩坑
- 六、完整训练闭环
- 模型规模
- 七、上机实操流程与验收标准
- 7.1 查看训练输出文件
- 7.2 单句翻译(加载 best_model.chkpt 推理)
- 7.3 异常处理与注意点
- 7.4 验收留存内容
- 八、上机实操流程与验收标准
- 九、学习收获与踩坑总结
前言
最近学习沐曦第二课,实操在国产GPU MetaX C500上,基于mcPyTorch跑Transformer的Encoder-Decoder英中翻译模型。整套课程覆盖数据集预处理、BPE分词、Transformer注意力、Mask机制、国产GPU迁移、完整训练闭环,踩了不少概念坑,在这里做学习总结,方便后续复盘。
硬件环境:沐曦C500;软件栈:mcPyTorch,兼容PyTorch接口,业务代码几乎不用修改即可完成国产GPU迁移。
一、课程整体概览
本课实现英中机器翻译,对比CPU版本有四处关键改动:
| 项目 | CPU版本 | 本课(C500+mcPyTorch) |
|---|---|---|
| 语料 | 代码内置少量句对 | Tatoeba英中平行语料 |
| 注意力 | 直接调用框架封装 | 自行实现缩放点积注意力,手动补齐逻辑 |
| 代码组织 | 单文件 | 分层模块化代码 |
| 运行设备 | CPU | 沐曦C500国产GPU |
整体模型结构:Encoder×3层 + Decoder×3层,从分词、词表映射、位置编码,到自注意力、交叉注意力、多头切分、Mask控制,最后完成训练闭环。
二、训练环境:沐曦C500 + mcPyTorch
1. 环境组成
- 计算卡:MetaX C500,单卡显存64GB
- 驱动:Kernel Mode Driver 3.3.12;MACA 3.2.1.10
- 框架:mcPyTorch 2.6.0+metax3.2.1.3,是沐曦适配PyTorch的版本,提供CUDA兼容接口
- 监控工具:
mx-smi 2.2.9,相当于国产GPU的nvidia-smi
2. 上机前三项自检(必做)
- 打印框架版本:版本后缀带
metax,确认不是官方原版PyTorch; torch.cuda.is_available()返回True,代表兼容接口正常;- 跑一次简单张量运算,验证计算通路可用。
⚠️重要坑:安装依赖包必须带上--no-deps,不然会自动安装标准pytorch,直接覆盖mcPyTorch。镜像必须选择PyTorch-Agent镜像。核心设计:上层模型、训练脚本、数据处理业务代码完全不动,仅仅替换底层运行时和算子库,实现国产GPU迁移。
三、数据集:Tatoeba英中平行语料
Tatoeba是开源多语言例句库,脚本自动下载eng-cmn句对,按照8:1:1切分训练集、验证集、测试集。
- 训练集4.75MB(80%):更新模型参数
- 验证集0.61MB(10%):判断何时保存Checkpoint
- 测试集0.68MB(10%):训练结束评估翻译质量
虽然数据集整体大小只有二十余MB,但一轮训练约967个batch,训练多轮后总计算量巨大,因此必须使用GPU加速。
预处理流程:下载筛选句对 → 英文空格分词,中文逐字拆分 → 学习BPE合并规则生成子词词表 → 切分三份数据集。
四、文本输入处理:分词、BPE、词表、位置编码
1. 原始文本到模型输入两步转换
原始字符串 → 分词得到token → 查询词表映射为整数ID → 查表Embedding矩阵,得到256维向量。
本课Embedding矩阵约1.1万×256。中文不像英文没有空格,不能直接空格切分,需要BPE子词切分。
2. 为什么选择BPE子词切分
三种分词方案对比:
- 按词切分:词表爆炸,大量未登录词;中文无空格无法直接使用;
- 按字符切分:词表很小,但序列拉得很长,语义单元被打散;
- BPE子词切分:主流大模型方案(GPT、BERT、T5底层思想),统计语料符号对频次,反复合并最高频相邻符号,词表可控,几乎没有未登录词。
本课设置合并8000次,源端目标端共用一套词表。中文先拆成单字符,再由BPE学习组合片段。
3. 特殊符号索引坑点
CPU版本:PAD填充符编号硬编码=0;
本课:词表由语料统计生成,UNK=0,PAD=1,BOS=2,EOS=3。
大坑:不能硬编码PAD=0!如果继续写死0,会屏蔽未登录符,训练loss正常下降,但模型输出结果完全错误。特殊符号索引必须从词表读取。
4. 位置编码
注意力本身对输入顺序不敏感,打乱token顺序输出向量不变,必须显式注入位置信息。
- 实现:正弦余弦生成位置向量,直接和词向量相加(不是拼接),维度保持不变;
- 位置编码不参与梯度更新,不属于模型可训练参数;
- 本课通过预处理过滤超长句子,上限80。
五、Transformer Encoder-Decoder核心机制
1. Encoder与Decoder分工
- Encoder:源语言句子只编码一次,输出
enc_output,后续解码全程复用,不重复计算源句; - Decoder:逐步生成目标语言,每一步解码都拿Encoder输出当作K、V做交叉注意力;
- 最后把Decoder输出投射到词表,输出Logits,不是概率。
性能关键点:同一个源句一次翻译只跑一遍Encoder,减少大量重复计算。
2. 缩放点积注意力四步(本课手动实现)
- 缩放点积:Q和K转置相乘,除以√d_k做缩放;
- Mask屏蔽:mask需要屏蔽位置填充极小值-1e9;
- Softmax归一化+dropout;
- 和V加权求和,输出与Q形状一致。
attn = torch.matmul(q / self.temperature, k.transpose(2,3)) if mask is not None: attn = attn.masked_fill(mask == 0, -1e9) attn = self.dropout(F.softmax(attn, dim=-1)) output = torch.matmul(attn, v)3. 三处注意力,分清Q/K/V来源
- Encoder自注意力:Q/K/V全部来自Encoder输入;仅Padding-Mask;句内所有token可以互相看见;
- Decoder自注意力:Q/K/V全部来自Decoder输入;同时使用Padding Mask + Causal因果Mask,看不到未来位置token;
- 交叉注意力:Q来自Decoder,K、V来自Encoder输出!⚠️这里绝对不能加因果mask,翻译时源句全文可见。
4. 多头注意力
误区:多头不是复制多份完整模型!
本课配置d_model=256,head=4,把256维切分为4个64维子空间,每个头独立运算,最后拼接。参数量、计算量基本不变,多个子空间捕捉不同维度语义。
5. Mask组合,极易踩坑
目标端Decoder的mask =Padding Mask & Causal因果Mask(按位与)
- Padding Mask:屏蔽PAD填充占位;
- Causal Mask(下三角):屏蔽未来时刻token,防止看到还没有生成的词;
⚠️布尔取值大坑:不同框架Mask约定不一样!本课约定:True代表保留可见,False代表屏蔽。写反mask程序不会报错,loss还会下降,但是翻译结果完全不通顺,很难排查。六、完整训练闭环
训练闭环五步:
- 数据加载:把张量迁移到GPU设备;
- 前向计算模型输出Logits;
- 损失计算:CrossEntropy,设置
ignore_index跳过PAD填充位置。
重点:不加ignore_index,填充位参与loss计算,损失被稀释,梯度被无意义的PAD干扰,指标虚假好看;- 反向传播+参数更新,调整学习率;
- 每个epoch结束保存权重:只保留验证集loss最低的checkpoint。
1-4每一个batch循环执行;第5步每个epoch执行一次。
模型规模
本课模型总参数量约1170万,fp32常驻显存约178MB,加上激活约400MB。虽然CPU内存可以装下模型,但是整体迭代总计算量巨大,训练阶段必须GPU。
设备迁移:仅仅一行torch.device('cuda' if opt.cuda else 'cpu'),mcPyTorch兼容CUDA接口,上层代码一行不用改。
七、上机实操流程与验收标准
仓库参考疑修-ODTCAIInfra/Transformer实战营
训练完成之后,最优权重会自动保存到outputs/en_zh/best_model.chkpt,该文件同时保存模型权重、训练配置、词表相关信息,是我们后续推理的核心。
7.1 查看训练输出文件
#查看输出目录文件 ls -lh outputs/en_zh/ #查看测试集批量翻译结果 head -5 outputs/en_zh/predictions.txt⚠️注意:predictions.txt是BPE子词直接输出,文本里面会出现@@标记,@@代表子词接续,需要把带@@的片段和后面token拼接,才是可读中文。批量文件不会自动做拼接;但是单句翻译脚本会自动完成子词拼接与整理,不需要手动处理@@符号。
7.2 单句翻译(加载 best_model.chkpt 推理)
python -m transformer.Translator_en_zh -src "i love machine learning"执行之后会加载最优checkpoint,完成BPE分词、Encoder编码、Decoder自回归解码、子词拼接,输出通顺译文。
7.3 异常处理与注意点
- 推理报错,大概率是Checkpoint与预处理生成的
.pkl词表文件不匹配,必须使用本次训练配套生成的数据文件,混用旧的pkl会出现乱码、译文错乱; - 如果需要自定义最大句长,不能直接改训练参数,要重新运行预处理脚本生成新数据集:
python preprocess_en_zh.py --tatoeba --max_len 60 \ -prefix tatoeba_en_zh_len60 -save_data tatoeba_en_zh_len60.pkl #指定新数据集启动训练 DATA_PKL=dataset/en_zh/tatoeba_en_zh_len60.pkl \ BATCH_SIZE=64 ./scripts/run_c500_tatoeba_en_zh.sh- 数据集包含简、繁体混合中文,预处理脚本没有做简繁归一,译文会同时出现简体、繁体字符,属于正常现象;
- 评估验收留存材料:记录源句子、模型输出译文,不需要强行追求完美翻译质量;只要译文和源句语义能够对应,即为合格。
- 如果训练中途中断:只有已经生成的
best_model.chkpt可以拿来推理;务必保留完整日志,记录中断现象,不要直接删除日志重跑覆盖记录。
7.4 验收留存内容
- 目录
outputs/en_zh/下best_model.chkpt文件信息; - 单句翻译源句与输出译文;
- 查看
train.log、valid.log确认损失整体下降趋势; - 留存
predictions.txt批量输出样例,理解@@子词接续标记。
八、上机实操流程与验收标准
- 创建实例拉取代码,创建实例镜像必须选PyTorch‑Agent;
- 完成环境三项自检;
- 对照源码练习缩放点积注意力、Padding Mask、Causal Mask;
- 门禁步骤:打印 Mask 矩阵核对,屏蔽位置必须正确,未通过禁止启动训练;
- 启动训练,观察日志模型配置、pad 索引、warmup 警告、每个 epoch 批次数量;
- 另起终端执行
mx‑smi,记录显存占用、GPU 利用率; - 训练结束,加载 best_model.chkpt 做推理翻译测试句子;
九、学习收获与踩坑总结
- 国产GPU迁移的体验:mcPyTorch做到上层业务代码零修改,替换底层运行时就完成迁移。坑集中在环境镜像选择、依赖安装,一旦把标准PyTorch装上去环境直接坏掉。
- Mask是Transformer最隐蔽的坑:Mask布尔值的定义不同库不一样,写反不会抛异常,loss依旧下降,但是翻译完全乱掉,必须打印矩阵肉眼核对,作为门禁测试。Decoder目标端Mask需要同时做padding+因果掩码;交叉注意力千万不能加因果mask。
- 词表特殊符号不能硬编码:当词表由语料学习生成,PAD、UNK编号不是固定0,必须从词表读取索引,否则训练正常,逻辑完全错误。
- BPE子词理解:解决未登录词和词表爆炸,中文处理流程:先拆字符,再合并高频片段。
- Encoder输出复用:源句子只编码一次,每一步解码复用编码结果,是Transformer翻译推理的性能关键点。
- Loss计算一定要忽略PAD,
ignore_index必不可少,不然填充token污染梯度。 - 模型大小不大不等于训练可以用CPU:参数量小,但迭代轮次多、batch多,累计FLOPs巨大,训练阶段GPU加速不可缺少。
本次实验完整走通从环境搭建、数据预处理、核心注意力实现、mask编写、国产卡训练、监控、保存checkpoint推理的全流程,对Transformer机器翻译底层细节、国产GPU工程实践有了非常直观理解。