昇思MindSpore进阶教程--在ResNet-50网络上应用二阶优化实践(下)
大家好,我是刘明,明志科技创始人,华为昇思MindSpore布道师。
技术上主攻前端开发、鸿蒙开发和AI算法研究。
努力为大家带来持续的技术分享,如果你也喜欢我的文章,就点个关注吧
文章上半部分请查看
在ResNet-50网络上应用二阶优化实践(上)
训练网络
配置模型保存
MindSpore提供了callback机制,可以在训练过程中执行自定义逻辑,这里使用框架提供的ModelCheckpoint函数。 ModelCheckpoint可以保存网络模型和参数,以便进行后续的fine-tuning操作。 TimeMonitor、LossMonitor是MindSpore官方提供的callback函数,可以分别用于监控训练过程中单步迭代时间和loss值的变化。
import mindspore as ms
from mindspore.train import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitorif __name__ == "__main__":# define callbackstime_cb = TimeMonitor(data_size=step_size)loss_cb = LossMonitor()cb = [time_cb, loss_cb]if config.save_checkpoint:config_ck = CheckpointConfig(save_checkpoint_steps=config.save_checkpoint_epochs * step_size,keep_checkpoint_max=config.keep_checkpoint_max)ckpt_cb = ModelCheckpoint(prefix="resnet", directory=ckpt_save_dir, config=config_ck)cb += [ckpt_cb]
配置训练网络
通过MindSpore提供的model.train接口可以方便地进行网络的训练。THOR优化器通过降低二阶矩阵更新频率,来减少计算量,提升计算速度,故重新定义一个ModelThor类,继承MindSpore提供的Model类。在ModelThor类中获取THOR的二阶矩阵更新频率控制参数,用户可以通过调整该参数,优化整体的性能。 MindSpore提供Model类向ModelThor类的一键转换接口。
import mindspore as ms
from mindspore import amp
from mindspore.train import Model, ConvertModelUtilsif __name__ == "__main__":...loss_scale = amp.FixedLossScaleManager(config.loss_scale, drop_overflow_update=False)model = Model(net, loss_fn=loss, optimizer=opt, loss_scale_manager=loss_scale, metrics=metrics,amp_level="O2", keep_batchnorm_fp32=False, eval_network=dist_eval_network)if cfg.optimizer == "Thor":model = ConvertModelUtils().convert_to_thor_model(model=model, network=net, loss_fn=loss, optimizer=opt,loss_scale_manager=loss_scale, metrics={'acc'},amp_level="O2", keep_batchnorm_fp32=False) ...
运行脚本
训练脚本定义完成之后,调scripts目录下的shell脚本,启动分布式训练进程。
Atlas训练系列产品
目前MindSpore分布式在Ascend上执行采用单卡单进程运行方式,即每张卡上运行1个进程,进程数量与使用的卡的数量一致。进程均放在后台执行,每个进程创建1个目录,目录名称为train_parallel+ device_id,用来保存日志信息,算子编译信息以及训练的checkpoint文件。下面以使用8张卡的分布式训练脚本为例,演示如何运行脚本。
使用以下命令运行脚本:
bash run_distribute_train.sh <RANK_TABLE_FILE> <DATASET_PATH> [CONFIG_PATH]
脚本需要传入变量RANK_TABLE_FILE,DATASET_PATH和CONFIG_PATH,其中:
-
RANK_TABLE_FILE:组网信息文件的路径。(rank table文件的生成,参考HCCL_TOOL)
-
DATASET_PATH:训练数据集路径。
-
CONFIG_PATH:配置文件路径。
其余环境变量请参考安装教程中的配置项。
训练过程中loss打印示例如下:
epoch: 1 step: 5004, loss is 4.4182425
epoch: 2 step: 5004, loss is 3.740064
epoch: 3 step: 5004, loss is 4.0546017
epoch: 4 step: 5004, loss is 3.7598825
epoch: 5 step: 5004, loss is 3.3744206epoch: 40 step: 5004, loss is 1.6907625
epoch: 41 step: 5004, loss is 1.8217756
epoch: 42 step: 5004, loss is 1.6453942
训练完后,每张卡训练产生的checkpoint文件保存在各自训练目录下,device_0产生的checkpoint文件示例如下:
└─train_parallel0├─ckpt_0├─resnet-1_5004.ckpt├─resnet-2_5004.ckpt│ ......├─resnet-42_5004.ckpt│ ......
其中, *.ckpt:指保存的模型参数文件。checkpoint文件名称具体含义:网络名称-epoch数_step数.ckpt。
GPU
在GPU硬件平台上,MindSpore采用OpenMPI的mpirun进行分布式训练,进程创建1个目录,目录名称为train_parallel,用来保存日志信息和训练的checkpoint文件。下面以使用8张卡的分布式训练脚本为例,演示如何运行脚本。
使用以下命令运行脚本:
bash run_distribute_train_gpu.sh <DATASET_PATH> <CONFIG_PATH>
脚本需要传入变量DATASET_PATH和CONFIG_PATH,其中:
-
DATASET_PATH:训练数据集路径。
-
CONFIG_PATH:配置文件路径。
在GPU训练时,无需设置DEVICE_ID环境变量,因此在主训练脚本中不需要调用int(os.getenv(‘DEVICE_ID’))来获取卡的物理序号,同时context中也无需传入device_id。我们需要将device_target设置为GPU,并需要调用init()来使能NCCL。
训练过程中loss打印示例如下:
epoch: 1 step: 5004, loss is 4.2546034
epoch: 2 step: 5004, loss is 4.0819564
epoch: 3 step: 5004, loss is 3.7005644
epoch: 4 step: 5004, loss is 3.2668946
epoch: 5 step: 5004, loss is 3.023509epoch: 36 step: 5004, loss is 1.645802
训练完后,保存的模型文件示例如下:
└─train_parallel├─ckpt_0├─resnet-1_5004.ckpt├─resnet-2_5004.ckpt│ ......├─resnet-36_5004.ckpt│ ............├─ckpt_7├─resnet-1_5004.ckpt├─resnet-2_5004.ckpt│ ......├─resnet-36_5004.ckpt│ ......
模型推理
使用训练过程中保存的checkpoint文件进行推理,验证模型的泛化能力。首先通过load_checkpoint接口加载模型文件,然后调用Model的eval接口对输入图片类别作出预测,再与输入图片的真实类别做比较,得出最终的预测精度值。
定义推理网络
-
使用load_checkpoint接口加载模型文件。
-
使用model.eval接口读入测试数据集,进行推理。
-
计算得出预测精度值。
import mindspore as ms
from mindspore.train import Modelif __name__ == "__main__":...# define netnet = resnet(class_num=config.class_num)# load checkpointparam_dict = ms.load_checkpoint(args_opt.checkpoint_path)ms.load_param_into_net(net, param_dict)net.set_train(False)# define lossif args_opt.dataset == "imagenet2012":if not config.use_label_smooth:config.label_smooth_factor = 0.0loss = CrossEntropySmooth(sparse=True, reduction='mean',smooth_factor=config.label_smooth_factor, num_classes=config.class_num)else:loss = SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')# define modelmodel = Model(net, loss_fn=loss, metrics={'top_1_accuracy', 'top_5_accuracy'})# eval modelres = model.eval(dataset)print("result:", res, "ckpt=", args_opt.checkpoint_path)...
执行推理
推理网络定义完成之后,调用scripts目录下的shell脚本,进行推理。
Atlas训练系列产品
在Atlas训练系列产品平台上,推理的执行命令如下:
bash run_eval.sh <DATASET_PATH> <CHECKPOINT_PATH> <CONFIG_PATH>
脚本需要传入变量DATASET_PATH,CHECKPOINT_PATH和<CONFIG_PATH>,其中:
-
DATASET_PATH:推理数据集路径。
-
CHECKPOINT_PATH:保存的checkpoint路径。
-
CONFIG_PATH:配置文件路径。
目前推理使用的是单卡(默认device 0)进行推理,推理的结果如下:
result: {'top_5_accuracy': 0.9295574583866837, 'top_1_accuracy': 0.761443661971831} ckpt=train_parallel0/resnet-42_5004.ckpt
GPU
在GPU硬件平台上,推理的执行命令如下:
bash run_eval_gpu.sh <DATASET_PATH> <CHECKPOINT_PATH> <CONFIG_PATH>
脚本需要传入变量DATASET_PATH,CHECKPOINT_PATH和CONFIG_PATH,其中:
-
DATASET_PATH:推理数据集路径。
-
CHECKPOINT_PATH:保存的checkpoint路径。
-
CONFIG_PATH:配置文件路径。
推理的结果如下:
result: {'top_5_accuracy': 0.9287972151088348, 'top_1_accuracy': 0.7597031049935979} ckpt=train_parallel/resnet-36_5004.ckpt