• 【MindSpore易点通】常用性能调优方法经验总结


    本文给大家介绍几种常用的性能调优方法。

    调整数据处理进程数

    MindSpore Data中的某些算子接收num_parallel_workers参数,该参数设置了算子使用的线程数。根据物理内核的数量和目标系统的负载,增加管道中num_parallel_workers的值,可以提高性能。对于任何包含计算密集型Tensor运算(比如Decode)的Map算子而言,尤其如此。

    使用默认数据处理进程数(为1):

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

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

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

    运行后性能对比:使用默认数据处理进程数:2200 imgs/sec ;调整数据处理进程数为2:2300 imgs/sec

    使用MindRecord格式加载数据

    目前MindSpore Data支持的特定格式数据集为:MindRecord。使用MindRecord格式的加载数据性能更优。

    MindRecord数据加载流程:

    1. import mindspore.dataset as ds
    2. CV_FILE_NAME = "./cifar10.mindrecord"
    3. cifar_ds = ds.MindDataset(dataset_file=CV_FILE_NAME,columns_list=["data","label"], shuffle=True)

    运行后性能对比: 自定义数据集加载cifar10:850 imgs/sec;MindRecord格式加载cifar10:2200 imgs/sec

    加载数据集时shuffle

    数据集加载时shuffle,算子可以在生成输出Tensor之前对数据进行内部shuffle。与在管道中使用显式shuffle算子相比,这种内部shuffle通常会带来更好的性能。

    管道中使用显式shuffle:

    1. import mindspore.dataset as ds
    2. DATA_DIR = "./cifar-10-batches-bin/"
    3. cifar_ds = ds.Cifar10Dataset(DATA_DIR, usage='train')
    4. cifar_ds = cifar_ds.shuffle(buffer_size=10000)

    加载数据集时shuffle:

    1. import mindspore.dataset as ds
    2. DATA_DIR = "./cifar-10-batches-bin/"
    3. cifar_ds = ds.Cifar10Dataset(DATA_DIR, shuffle=True, usage='train')

    运行后性能对比:本样例未见明显性能收益

    混合精度

    混合精度训练方法是通过混合使用单精度和半精度数据格式来加速深度神经网络训练的过程,同时保持了单精度训练所能达到的网络精度。混合精度训练能够加速计算过程,同时减少内存使用和存取,并使得在特定的硬件上可以训练更大的模型或batch size。

    运行后性能对比:高阶API: 2200 imgs/sec ;高阶API混合精度: 3300 imgs/sec

                       低阶API: 2000 imgs/sec ;低阶API混合精度: 3200 imgs/sec

    数据下沉

    采用数据集的下沉模式,即训练计算下沉到硬件平台中执行,数据下沉可以优化训练性能。

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

    数据未下沉:

    model.train(..., dataset_sink_mode=False, ...)

    数据下沉:

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

    :低阶API不支持数据下沉,若想实现数据下沉请使用Model.train接口进行训练。

    运行后性能对比:数据未下沉:2000 imgs/sec;数据下沉:2200 imgs/sec

    避免c_transform和py_transform混用

    c_transform是在C++内维护buffer管理,py_transform是在python内维护buffer管理。因为python和C++切换的性能成本,建议不要混用算子,否则会降低训练性能。

    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")

    c_transform和py_transform未混用:

    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")

    运行后性能对比:c_transform和py_transform混用:1100 imgs/sec;

                  c_transform和py_transform未混用:2200 imgs/sec

    多map合并单map

    数据预处理时,Map算子可以接收Tensor算子列表,并将按顺序应用所有的这些算子。与为每个Tensor算子使用单独的Map算子相比,可以获得更好的性能。

    多map数据预处理:

    1. randomcrop_op = CV.RandomCrop((32, 32), (4, 4, 4, 4))
    2. randomhorizontalflip_op = CV.RandomHorizontalFlip()
    3. rescale_op = CV.Rescale(rescale, shift)
    4. normalize_op = CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
    5. hwc2chw_op = CV.HWC2CHW()
    6. if do_train:
    7.     cifar_ds = cifar_ds.map(operations=[randomcrop_op], input_columns="image")
    8.     cifar_ds = cifar_ds.map(operations=[randomhorizontalflip_op], input_columns="image")
    9. cifar_ds = cifar_ds.map(operations=[rescale_op], input_columns="image")
    10. cifar_ds = cifar_ds.map(operations=[normalize_op], input_columns="image")
    11. cifar_ds = cifar_ds.map(operations=[hwc2chw_op], input_columns="image")else:
    12. cifar_ds = cifar_ds.map(operations=[rescale_op], input_columns="image")
    13. cifar_ds = cifar_ds.map(operations=[normalize_op], input_columns="image")
    14. cifar_ds = cifar_ds.map(operations=[hwc2chw_op], input_columns="image")

    合并成单map数据预处理:

    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")

    运行后性能对比:本样例未见明显性能收益

    融合算子

    MindSpore Data提供某些融合算子,这些算子将两个或多个算子的功能聚合到一个算子中。 与它们各自组件的流水线相比,这种融合算子提供了更好的性能。一个很好的融合算子是RandomCropDecodeResizeOp,它执行解码,然后对任意给定的Tensor进行随机裁剪和大小调整。用户可以查看算子API文档查看是否有相应融合算子替代现有算子,以获得更好性能。

    自动数据加速

    MindSpore提供了一种自动数据调优的工具——Dataset AutoTune,用于在训练过程中根据环境资源的情况自动调整数据处理管道的并行度,最大化利用系统资源加速数据处理管道的处理速度。在整个训练的过程中,Dataset AutoTune模块会持续检测当前训练性能瓶颈处于数据侧还是网络侧。如果检测到瓶颈在数据侧,则将进一步对数据处理管道中的各个算子(如GeneratorDataset、map、batch此类数据算子)进行参数调整。

  • 相关阅读:
    Github高级搜索【指定日期区间,星星数,用户仓库名多条件精确搜索】
    QGIS添加在线底图
    直播美颜技术的技术背后:美颜SDK的原理与实践
    【计算机网络Part 2】数据链路层
    随机过程:布朗运动
    【论文阅读】机器翻译新范式,《A Paradigm Shift in Machine Translation》
    TensorFlow: An open-source software library for Machine Intelligence
    用AI原生向量数据库Milvus Cloud 搭建一个 AI 聊天机器人
    文字转语音怎么做?分享三种配音方法,真人语音很逼真
    Elasticsearch学习/调优
  • 原文地址:https://blog.csdn.net/Kenji_Shinji/article/details/127650614