“训练变慢了”还不是一个可操作的结论。可能是数据等待、编译、前向、反向、通信或评估。先定义测量对象,再决定优化哪里。
让两次实验真的可比
记录硬件、软件版本、精度、批次、序列长度和模型形状。把数据加载、首次编译、预热和稳定执行分开。若每次都换输入尺寸或同时改精度,比较结果就混入了其他因素。
至少重复多次,报告中位数及波动,而不是只挑最快的一次。吞吐可以用每秒处理的 token 数表达,但也要说明 token 计数是否包含 padding。
GPU 计时要处理异步执行
GPU 操作通常异步提交。CPU 计时器结束时,GPU 可能尚未算完。使用 CUDA event 或在合适位置同步,才知道真正的执行时间。下面是已有 CUDA 环境下的测量骨架,operation 由你的实验定义。
import time
import torch
for _ in range(5):
operation() # 预热,单独记录首次编译开销。
torch.cuda.synchronize()
start = time.perf_counter()
operation()
torch.cuda.synchronize()
elapsed = time.perf_counter() - start
print(elapsed)
CPU 实验不使用 CUDA 同步;应选择与设备匹配的工具。若测峰值显存,还要区分已分配内存和缓存保留内存,并固定测量区间。
优化后先检查正确性
改用更高效的注意力、混合精度或编译,可能改变数值表现和执行路径。使用固定输入检查输出误差、梯度和因果约束,再比较耗时。
对每个优化写清条件:它在什么输入规模下有效?是否额外占用内存?首次运行成本是否抵消了短任务的收益?不要把一个小尺寸操作的结果直接推广到整套训练系统。
给结课项目留下证据
本课产出一张对照表:基线与修改后在相同条件下的时间、吞吐、内存和正确性结果。没有 GPU 也可以完成 CPU 的小规模对照,只需明确测量范围。
下一课把这些结果与数据审计、模型实现和训练记录组合,交付一个别人能复现的语言模型项目。