AI开发平台MODELARTS-问题复现

时间:2024-12-30 17:37:11

问题复现

一般场景的训练模型都是包括随机种子、数据集Shuffle、网络结构Dropout等操作的,目的是在网络阶段引入一定的随机性使得训练结果更加具有鲁棒性。然而在精度诊断或者对齐阶段,这些随机性会导致训练运行结果每次表现不一致,无法进行和标杆的比对。因此在训练模型复现问题时,需要固定存在随机性的步骤,保证实验可重复性。存在随机性的步骤包括模型参数初始化,数据Batch加载顺序,Dropout层等。部分算子的计算结果也存在不确定性,需要固定。

当前固定随机性操作可分为工具固定人工固定两种。

  1. 工具固定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仅使用确定性的卷积算法。

  2. 工具固定(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
  3. 人工固定(硬件随机差异)

    工具内部对于随机的控制,是通过设定统一的随机种子进行随机性固定的。但是由于硬件的差异,会导致同样的随机种子在不同硬件上生成的随机数不同。具体示例如下:

    由上图可见,torch.randn在GPU和NPU上固定随机种子后,仍然生成不同的随机张量。

    对于上述场景,用户需要将网络中的randn在CPU上完成后再转到对应device。例如,StableDiffusion中需要在forward过程中逐步生成随机噪声。

    这样在Host侧生成的随机张量能够保证一样,搬移到NPU或者GPU设备上仍然一样。

    固定随机性完成后,可以使用缩小的模型在单机环境进行问题复现。复现后使用下一章节介绍的msprobe工具进行问题定位。需要注意的是,部分模型算法本身存在固有的随机性,在使用上述方法固定随机性后,如果使用工具也未能找到出问题的API,需要分析是否由算法本身的随机性导致。

support.huaweicloud.com/bestpractice-modelarts/toctopics/zh-cn_topic_0000002017200552.html