• 【MindSpore易点通】如何根据profiler数据查看性能瓶颈


    MindInsight主要功能介绍

    MindInsight详细功能介绍请参考MindInsight性能调试

    MindInsight主页面包括主要功能的概览信息:迭代轨迹、算子耗时统计、数据准备、时间线、调优助手。

    迭代轨迹:展示了每个迭代各个阶段的性能信息:包括迭代间隙、前向反向、迭代拖尾以及每个all_reduce的信息。下方展示各个阶段的变化趋势。

    算子耗时统计:通过类型、详细信息两个维度展示AICORE和AICPU算子耗时统计信息。

    数据准备:性能分析分为两部分:1、迭代间隙数据处理分析;2、数据处理pipeline分析。

    迭代间隙阶段:下图展示了迭代间隙阶段执行的操作的流程,通过分析队列中数据的情况判断出现性能问题的步骤。

    数据处理阶段:分析用于已经定位到了该阶段的问题时,定位其中哪个算子存在问题,通过各个算子之间的队列的使用率,判断前面的算子能否提供足够的数据到队列中供下一个算子使用。

    时间线:展示了算子在各个stream上的起止时刻,执行顺序、算子间隙、allreduce信息,从详细的粒度展示算子执行情况。

    用户可参考下图,进行算子分析(常用的为MindData阶段分析和算子性能分析)。

    案例问题分析

    问题1:迭代间隙过长

    通过迭代轨迹发现,迭代间隙过长:

    问题分析

    1.迭代间隙过长,通常因为数据处理过程导致,进入数据处理阶段分析。

    2.主机队列几乎为空,判定是数据处理算子问题,进入数据处理pipeline查看具体问题。

    3.当算子左边连接的Queue使用率都比较高,右边连接的Queue使用率比较低时,该算子可能是性能瓶颈:图中红框内数据可以看出,map操作过程中的队列使用率高,而右边连接的队列使用率较低,判断map中的数据处理过程存在性能瓶颈。

    4.分析map中数据处理相关代码:发现数据处理进程数为默认值1,可以尝试调整数据处理进程数。

    5.分析map中数据处理相关代码:发现存在c_transform和py_transform混用的问题,降低了训练性能。

    措施1:调整数据处理进程数

    调整数据处理进程数为8:

    1. if do_train:
    2.     cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, num_parallel_workers=8, shuffle=True, usage='train')
    3. else:
    4.     cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, num_parallel_workers=8, shuffle=False, usage='test')
    5. cifar_ds = cifar_ds.map(operations=transform_label, num_parallel_workers=8, python_multiprocessing=True, input_columns="label")
    6. cifar_ds = cifar_ds.map(operations=transform_data, num_parallel_workers=8, python_multiprocessing=True, python_multiprocessing=True, input_columns="image")
    7. cifar_ds = cifar_ds.batch(batch_size, num_parallel_workers=8, drop_remainder=True)

    修改后,重新训练,将训练后代码继续做profiling,发现迭代间隙明显缩短。

    性能对比: 改进前:1100imgs/sec 改进后: 2150imgs/sec

    措施2:避免c_transform和py_transform混用

    数据处理过程中发现存在c_transform和py_transform混用的情况:

    1. if do_train:
    2.     # Transformation on train data
    3. transform_data = py_trans.Compose([
    4.             CV.RandomCrop((32, 32), (4, 4, 4, 4)),
    5.             py_vision.ToPIL(),
    6.             py_vision.RandomHorizontalFlip(),
    7.             CV.Rescale(rescale, shift),
    8.             CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
    9.             CV.HWC2CHW()
    10.             ])
    11. else:
    12.     # Transformation on validation data
    13.     transform_data = py_trans.Compose([
    14.             CV.Rescale(rescale, shift),
    15.             CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
    16.             CV.HWC2CHW()
    17.             ])          
    18. cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")

    将数据处理过程中代码进行如下修改:

    1. if do_train:
    2.         # Transformation on train data
    3.         transform_data = C.Compose([
    4.             CV.RandomCrop((32, 32), (4, 4, 4, 4)),
    5.             CV.RandomHorizontalFlip(),
    6.             CV.Rescale(rescale, shift),
    7.             CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
    8.             CV.HWC2CHW()])
    9.     else:
    10.         # Transformation on validation data
    11.         transform_data = C.Compose([
    12.             CV.Rescale(rescale, shift),
    13.             CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
    14.             CV.HWC2CHW()])
    15. cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")

    修改后,重新训练,将训练后代码继续做profiling。迭代间隙有所缩短。

    性能对比: 改进前:2150imgs/sec 改进后: 2250imgs/sec

    经过这两步优化,迭代间隙由原来的77.5027ms减少到17.0623ms,有明显改善。

    问题2:数据队列为空

    继续分析优化后的Profiler数据,发现数据准备中的主机队列几乎为空:

    问题分析

    1. 进入数据处理pipeline查看具体问题。

    2.如红框所示,数据处理过程中的队列使用率高。对于最右侧的算子,如果其左边所有Queue的使用率都比较高,该算子可能是性能瓶颈。而此处最右侧算子为框架自动插入算子,因此判断数据下发存在性能瓶颈,应提升数据从Host传输到Device的速度。

    措施3:采用数据下沉模式

    采用数据下沉模式,实现整图下沉到Device执行,避免Host-Device频繁交互,减小了数据传输开销。

    将Model.train接口中dataset_sink_mode值设为True,即可采用数据下沉模式。

    model.train(..., dataset_sink_mode=True, sink_size=steps_per_epoch_train)

    修改后,重新训练,将训练后代码继续做profiling,发现主机队列为空比例大大下降。

    数据处理过程中的队列使用率明显降低。

    性能对比: 改进前:2250imgs/sec 改进后: 2350imgs/sec

    问题3:前向+反向时间较长

    继续分析优化后的Profiler数据,由迭代轨迹看出,前反向时间相对较长,可能存在优化空间:

    措施4:使用混合精度

    使用混合精度可以加速训练,减少前反向时间。

    修改高阶API代码中的Model接口,将amp_level设置成"O3",网络将采用FP16进行训练。

    net = Model(net, loss, opt, metrics=metrics, amp_level="O3")

    修改后,重新训练,将训练后代码继续做profiling。发现前反向时间明显减少。

    性能对比: 改进前:2350imgs/sec 改进后: 3500imgs/sec

    经过以上优化,训练性能得到明显提升。由初始的1100imgs/sec,改进到3500imgs/sec。

  • 相关阅读:
    软考高级系统架构设计师系列之:案例分析典型试题五
    egg中的一些基本使用注意事项以及如何跨域(CORS)、JSONP、Proxy
    刷题笔记之十一 (计算字符串的编辑距离+微信红包+年终奖+迷宫问题+星际密码+数根)
    每日五问(java)
    基于inotify实现落盘文件的跨进程实时读写交互
    命名空间namespace
    .Net-C#文件上传的常用几种方式
    推荐 5 个不错的 React Native UI 库
    3474. 坠落的蚂蚁
    “闭关修炼”,吃透这本Java核心知识,跳槽面试不心慌
  • 原文地址:https://blog.csdn.net/Kenji_Shinji/article/details/127727136