问题复现
一般场景的训练模型都是包括随机种子、数据集Shuffle、网络结构Dropout等操作的,目的是在网络阶段引入一定的随机性使得训练结果更加具有鲁棒性。然而在精度诊断或者对齐阶段,这些随机性会导致训练运行结果每次表现不一致,无法进行和标杆的比对。因此在训练模型复现问题时,需要固定存在随机性的步骤,保证实验可重复性。存在随机性的步骤包括模型参数初始化,数据Batch加载顺序,Dropout层等。部分算子的计算结果也存在不确定性,需要固定。
当前固定随机性操作可分为工具固定和人工固定两种。
- 工具固定Seed
对于网络中随机性的固定,Msprobe提供了固定Seed的方式,只需要在config.json文件中添加对应seed配置即可。
Msprobe工具提供了seed_all接口用于固定网络中的随机数。如果客户使用了工具但取用了其他随机种子,则必须使用客户的随机种子固定随机性。
函数原型
from msprobe.pytorch.common import seed_all seed_all(seed=1234, mode=False)
表1 参数说明 参数名
说明
是否必选
seed
随机数种子。参数示例:seed=1000。默认值:1234。
否
mode
确定性计算模式。可配置True或False。参数示例:mode=True。默认值:False。
即使在相同的硬件和输入下,API多次执行的结果也可能不同,开启确定性计算是为了保证在相同的硬件和输入下,API多次执行的结果相同。
确定性计算会导致API执行性能降低,通常不需要在精度问题刚开始定位时就开启,而是建议在发现模型多次执行结果不同的情况下时再开启。
rnn类算子、ReduceSum、ReduceMean等算子可能与确定性计算存在冲突,如果开启确定性计算后多次执行的结果不相同,则考虑存在这些算子。
否
函数示例
seed_all函数的随机数种子,取默认值即可,无须配置;第二个参数默认关闭,不开启确定性计算时也无须配置。
确定性计算是NPU的一套机制,用于保证算子的计算确定性。之所以要有这个机制,是为了在Debug过程中,让所有的算子计算结果前后完全一致可复现,这是大多数精度问题分析的重要前提。因此,在精度问题定位过程中,确定性计算不是目的,而是手段。很多场景下需要在确定性计算使能的情况下,进行下一步的精度问题分析定位。Cuda对部分算子实现了确定性计算,但仍有部分算子无法固定。通常需要依赖确定性计算的场景是长稳问题,因为长稳问题需要通过多次长跑来分析Loss情况,这时候如果NPU本身计算结果不确定,就难以支撑和GPU结果的多次对比。
示例1:仅固定随机数,不开启确定性计算。
seed_all()
示例2:固定随机数,开启确定性计算。
seed_all(mode=True)
在多卡训练场景下由于通信算子计算累加计算顺序不确定,需要添加以下环境变量,固定通信算子计算的确定性:
export HCCL_DETERMINISTIC=TRUE
固定随机数范围
seed_all函数可固定随机数的范围如下表所示。
API
固定随机数
os.environ['PYTHONHASHSEED'] = str(seed)
禁止Python中的hash随机化。
random.seed(seed)
设置random随机生成器的种子。
np.random.seed(seed)
设置numpy中随机生成器的种子。
torch.manual_seed(seed)
设置当前CPU的随机种子。
torch.cuda.manual_seed(seed)
设置当前GPU的随机种子。
torch.cuda.manual_seed_all(seed)
设置所有GPU的随机种子。
torch_npu.npu.manual_seed(seed)
设置当前NPU的随机种子。
torch_npu.npu.manual_seed_all(seed)
设置所有NPU的随机种子。
torch.backends.cudnn.enable=False
关闭cuDNN。
torch.backends.cudnn.benchmark=False
cuDNN确定性地选择算法。
torch.backends.cudnn.deterministic=True
cuDNN仅使用确定性的卷积算法。
- 工具固定(Dropout)
Dropout的实质是以一定概率使得输入网络的数据某些位置元素的数值变为0,这样可以使得模型训练更加有效。但在精度问题的定位过程之中,需要避免产生这种问题,因此需要关闭Dropout。
在导入PrecisionDebugger后,工具会自动将如下接口参数p(丢弃概率)置为0。
torch.nn.functional.dropout torch.nn.functional.dropout2d torch.nn.functional.dropout3d torch.nn.Dropout torch.nn.Dropout2d torch.nn.Dropout3d
- 人工固定(硬件随机差异)
工具内部对于随机的控制,是通过设定统一的随机种子进行随机性固定的。但是由于硬件的差异,会导致同样的随机种子在不同硬件上生成的随机数不同。具体示例如下:
由上图可见,torch.randn在GPU和NPU上固定随机种子后,仍然生成不同的随机张量。
对于上述场景,用户需要将网络中的randn在CPU上完成后再转到对应device。例如,StableDiffusion中需要在forward过程中逐步生成随机噪声。
这样在Host侧生成的随机张量能够保证一样,搬移到NPU或者GPU设备上仍然一样。
固定随机性完成后,可以使用缩小的模型在单机环境进行问题复现。复现后使用下一章节介绍的msprobe工具进行问题定位。需要注意的是,部分模型算法本身存在固有的随机性,在使用上述方法固定随机性后,如果使用工具也未能找到出问题的API,需要分析是否由算法本身的随机性导致。