• 【MindSpore易点通】性能调试经验总结下篇


    背景信息

    MindSpore使用model.train接口训练时,默认同步保存模型,可能影响训练性能。

    经验总结内容

    在模型定义中配置async_save参数为True,即可实现异步保存模型,提升训练性能。

    1. config_ck = CheckpointConfig(save_checkpoint_steps=steps_per_epoch_train, keep_checkpoint_max=epoch_max, async_save=True)
    2. ckpoint_cb = ModelCheckpoint(prefix="train_resnet_cifar10", directory="./", config=config_ck)
    3. model.train(..., callbacks=[ckpoint_cb, ...], ...)

    性能对比:异步保存模型:2450 imgs/sec;同步保存模型:2200 imgs/sec

    自动数据加速

    背景信息

    MindSpore提供了一种自动数据调优的工具——Dataset AutoTune,用于在训练过程中根据环境资源的情况自动调整数据处理管道的并行度, 最大化利用系统资源加速数据处理管道的处理速度。

    在整个训练的过程中,Dataset AutoTune模块会持续检测当前训练性能瓶颈处于数据侧还是网络侧。如果检测到瓶颈在数据侧,则将 进一步对数据处理管道中的各个算子(如GeneratorDataset、map、batch此类数据算子)进行参数调整。

    1、示例代码

    示例代码如下:

    1. import mindspore.dataset as ds
    2. def create_dataset(...)
    3.     """
    4.     create dataset for train or test
    5.     """
    6.     # 使能自动数据加速
    7.     ds.config.set_enable_autotune(True)
    8.     # 其他数据集代码无需变更
    9.     data_set = ds.Cifar10Dataset(data_path)
    10.     ...

    自动数据加速关键代码:

    1. import mindspore.dataset as ds
    2. ds.config.set_enable_autotune(True)

    注:

    • 自动数据加速目前仅可用于下沉模式(dataset_sink_mode=True),在非下沉模式(dataset_sink_mode=False)下,Dataset AutoTune将不会生效,但不会影响网络正常训练;
    • Profiling性能分析和自动数据加速无法同时开启,否则会导致Profiling或Dataset AutoTune不生效。如果这样同时开启此两个功能,则会有一条警告信息提示用户检查是否为误操作。因此在使用Dataset AutoTune时,用户需要确保关闭Profiling功能。

    2、运行结果分析

    以示例代码为例使能数据自动加速功能,随后自动数据加速模块会通过打屏log的形式展示其对于性能瓶颈的分析情况:

    1. [WARNING] ME(15918,fffde27fc1e0,python):2022-01-13-09:33:16.061.926 [mindspore/ccsrc/minddata/dataset/engine/perf/auto_tune.cc:425] Analyse] Op (BatchOp(ID:2)) getting low average worker cpu utilization 1.25694% < 35% threshold.
    2. [WARNING] ME(15918,fffde27fc1e0,python):2022-01-13-09:33:16.061.941
    3. [mindspore/ccsrc/minddata/dataset/engine/perf/auto_tune.cc:359]
    4. RequestConnectorCapacityChange] Added request to change "prefetch_size" of Operator: BatchOp(ID:2)From old value: [32] to new value: [36].
    5. Epoch:8, 2703.92imgs/sec
    6. epoch time: 22154.670 ms, per step time: 47.339 ms

    数据管道的性能分析和调整过程可以通过上述的log体现:

    当检测到数据侧为瓶颈且需要发生参数变更时,则会通过WARNING级别的LOG信息提醒用户正在调整的参数。

    BatchOp(ID:2)From old value: [32] to new value: [36]

    在数据处理管道的初始配置下,Device Connector队列(数据管道与计算网络之间的缓冲队列)的利用率较低。

    [mindspore/ccsrc/minddata/dataset/engine/perf/auto_tune.cc:425] Analyse] Op (BatchOp(ID:2)) getting low average worker cpu utilization 1.25694% < 35% threshold.

    在使用示例代码运行20epoch加速前与加速后运行时间对比:

    自动数据加速后效果:

    未使用自动数据加速效果:

    MatMul、Tile、Div等算子最好把输入做16倍数对齐

    背景信息

    因为D芯片底层数据搬运按照16字节对齐,所以部分算子的输入在非16倍数的情况下无法使能多核,导致性能变差。

    经验总结内容

    MatMul、Tile以及Div算子的输入最好先向上进行16字节的对齐,以MatMul举例如下:

    1. import mindspore.nn as nn
    2. class CustomMatMul(nn.Cell):
    3.     def __init__(self, transpose_a=False, transpose_b=False):
    4.         super(CustomMatMul, self).__init__()
    5.         self.fc = P.MatMul(transpose_a=transpose_a, transpose_b=transpose_b)
    6.     def construct(self, x1, x2):
    7.         out = self.fc(x1, x2)
    8.         return out
    9. class MatMul_assignto16(nn.cell):
    10.     def __init__(self, args):
    11.         super(MatMul_assignto16, self).__init__()
    12.         self.num_classes = (args.num_classes // 16 + 1) * 16    #输入的类别数做向上16字节对齐
    13.         self.weight = Parameter(Tensor(np.ones((self.num_classes, args.emb_size)), mstype.float32), name="w", requires_grad=True)
    14.         self.fc = CustomMatMul(transpose_b=True).add_flags_recursive(fp16=True)
    15.     def construct(self, feature):
    16.         out = self.fc(feature, self.weight)
    17.         return out

    MatMul算子性能差

    背景信息

    D芯片中矩阵运算是用cube做的,只能支持fp16的计算类型

    经验总结内容

    MatMul算子尽量使用fp16的计算类型,fp32的MatMul是在aicpu上计算的,性能会比fp16差很多。 可以在me脚本层面手动指定算子的计算类型,如下:

    1. class CustomMatMul(nn.Cell):
    2.     def __init__(self, transpose_a=False, transpose_b=False):
    3.         super(CustomMatMul, self).__init__()
    4.         self.fc = P.MatMul(transpose_a=transpose_a, transpose_b=transpose_b)
    5.     def construct(self, x1, x2):
    6.         out = self.fc(x1, x2)
    7.         return out
    8. self.fc = CustomMatMul(transpose_b=True).add_flags_recursive(fp16=True)

    ResNet50跑ImageNet类别数设定

    背景信息

    ResNet50跑ImageNet在PyTorch上面的类别数设定是1000,而TensorFlow的类别数设定是1001。

    经验总结内容

    Ascend环境下针对TensorFlow做了更深度的优化,因此在跑MindSpore+Ascend的时候,也建议把类别数设置为1001以获取更加极致的性能。 可以在me脚本层面手动指定类别数,如下:

    1. class CommonHead(nn.Cell):
    2.     def __init__(self, num_classes=1001, out_channels):  #将类别数默认置为1001
    3.         super(CommonHead, self).__init__()
    4.         self.avgpool = GlobalAvgPooling()
    5.         self.fc = nn.Dense(out_channels, num_classes, has_bias=True)
    6.     def construct(self, x):
    7.         x = self.avgpool(x)
    8.         x = self.fc(x)
    9.         return x
  • 相关阅读:
    567.字符串中的排列
    vue2+element UI 树形只有两级, 第一级只能上下移动,第二级不能成为第一级,只能拖到别的第一级和在同一级排序
    Weblogic XMLDecoder 远程代码执行漏洞 CVE-2017-10271 漏洞复现
    ubuntu 查看5000端口是否开放
    【JavaEE多线程】深入解析Java并发工具类与应用实践
    Android eSIM-LPA基于Android13的实现
    十五、ROS的launch文件标签(一)
    OA系统开发
    预防山体滑坡,泥石流监测智能预警系统
    Flink的处理函数——processFunction
  • 原文地址:https://blog.csdn.net/Kenji_Shinji/article/details/127583159