保存模型

Ascend GPU CPU 模型导出

查看源文件    查看源文件

概述

在模型训练过程中,可以添加检查点(CheckPoint)用于保存模型的参数,以便执行推理及再训练使用。如果想继续在不同硬件平台上做推理,可通过网络和CheckPoint格式文件生成对应的MindIR、AIR和ONNX格式文件。

  • MindIR:MindSpore的一种基于图表示的函数式IR,定义了可扩展的图结构以及算子的IR表示,它消除了不同后端的模型差异。可以把在Ascend 910训练好的模型,在Ascend 310、GPU以及MindSpore Lite端侧上执行推理。

  • CheckPoint:MindSpore的存储了所有训练参数值的二进制文件。采用了Google的Protocol Buffers机制,与开发语言、平台无关,具有良好的可扩展性。CheckPoint的protocol格式定义在mindspore/ccsrc/utils/checkpoint.proto中。

  • AIR:全称Ascend Intermediate Representation,类似ONNX,是华为定义的针对机器学习所设计的开放式的文件格式,能更好地适配Ascend AI处理器。

  • ONNX:全称Open Neural Network Exchange,是一种针对机器学习所设计的开放式的文件格式,用于存储训练好的模型。

以下通过示例来介绍保存CheckPoint格式文件和导出MindIR、AIR和ONNX格式文件的方法。

保存CheckPoint格式文件

下面介绍两种保存checkpoint文件的方法。

使用callback机制

在模型训练的过程中,使用Callback机制传入回调函数ModelCheckpoint对象,可以保存模型参数,生成CheckPoint文件。

通过CheckpointConfig对象可以设置CheckPoint的保存策略。保存的参数分为网络参数和优化器参数。

ModelCheckpoint提供默认配置策略,方便用户快速上手。具体用法如下:

from mindspore.train.callback import ModelCheckpoint
ckpoint_cb = ModelCheckpoint()
model.train(epoch_num, dataset, callbacks=ckpoint_cb)

用户可以根据具体需求对CheckPoint策略进行配置。具体用法如下:

from mindspore.train.callback import ModelCheckpoint, CheckpointConfig
config_ck = CheckpointConfig(save_checkpoint_steps=32, keep_checkpoint_max=10)
ckpoint_cb = ModelCheckpoint(prefix='resnet50', directory=None, config=config_ck)
model.train(epoch_num, dataset, callbacks=ckpoint_cb)

上述代码中,首先需要初始化一个CheckpointConfig类对象,用来设置保存策略。

  • save_checkpoint_steps表示每隔多少个step保存一次。

  • keep_checkpoint_max表示最多保留CheckPoint文件的数量。

  • prefix表示生成CheckPoint文件的前缀名。

  • directory表示存放文件的目录。

创建一个ModelCheckpoint对象把它传递给model.train方法,就可以在训练过程中使用CheckPoint功能了。

生成的CheckPoint文件如下:

resnet50-graph.meta # 编译后的计算图
resnet50-1_32.ckpt  # CheckPoint文件后缀名为'.ckpt'
resnet50-2_32.ckpt  # 文件的命名方式表示保存参数所在的epoch和step数
resnet50-3_32.ckpt  # 表示保存的是第3个epoch的第32个step的模型参数
...

如果用户使用相同的前缀名,运行多次训练脚本,可能会生成同名CheckPoint文件。MindSpore为方便用户区分每次生成的文件,会在用户定义的前缀后添加”_”和数字加以区分。如果想要删除.ckpt文件时,请同步删除.meta 文件。

例:resnet50_3-2_32.ckpt 表示运行第3次脚本生成的第2个epoch的第32个step的CheckPoint文件。

  • 当执行分布式并行训练任务时,每个进程需要设置不同directory参数,用以保存CheckPoint文件到不同的目录,以防文件发生读写错乱。

CheckPoint配置策略

MindSpore提供了两种保存CheckPoint策略:迭代策略和时间策略,可以通过创建CheckpointConfig对象设置相应策略。 CheckpointConfig中共有四个参数可以设置:

  • save_checkpoint_steps:表示每隔多少个step保存一个CheckPoint文件,默认值为1。

  • save_checkpoint_seconds:表示每隔多少秒保存一个CheckPoint文件,默认值为0。

  • keep_checkpoint_max:表示最多保存多少个CheckPoint文件,默认值为5。

  • keep_checkpoint_per_n_minutes:表示每隔多少分钟保留一个CheckPoint文件,默认值为0。

save_checkpoint_stepskeep_checkpoint_max为迭代策略,根据训练迭代的次数进行配置。 save_checkpoint_secondskeep_checkpoint_per_n_minutes为时间策略,根据训练的时长进行配置。

两种策略不能同时使用,迭代策略优先级高于时间策略,当同时设置时,只有迭代策略可以生效。当参数显示设置为None时,表示放弃该策略。在迭代策略脚本正常结束的情况下,会默认保存最后一个step的CheckPoint文件。

断点续训

MindSpore提供了断点续训的功能,当用户开启该功能时,如果在训练过程中发生了异常,那么MindSpore会自动保存异常发生时的CheckPoint文件(临终CheckPoint)。断点续训的功能通过CheckpointConfig中的exception_save参数(bool类型)控制,设置为True时开启该功能,False关闭该功能,默认为False。断点续训功能保存的临终CheckPoint文件与正常流程保存的CheckPoint互不影响,命名机制和保存路径与正常流程设置保持一致,唯一不同之处在于会在临终CheckPoint文件名最后加上’_breakpoint’进行区分。

具体用法如下:

from mindspore.train.callback import ModelCheckpoint, CheckpointConfig
config_ck = CheckpointConfig(save_checkpoint_steps=32, keep_checkpoint_max=10, exception_save=True)
ckpoint_cb = ModelCheckpoint(prefix='resnet50', directory=None, config=config_ck)
model.train(epoch_num, dataset, callbacks=ckpoint_cb)

如果在训练过程中发生了异常,那么会自动保存临终CheckPoint,假如在训练中的第10个epoch的第10个step中发生异常,保存的临终CheckPoint文件如下:

resnet50-10_10_breakpoint.ckpt  # 临终CheckPoint文件名最后会加上'_breakpoint'与正常流程CheckPoint区分开。

使用save_checkpoint方法

可以使用save_checkpoint函数把自定义信息保存成 checkpoint文件,函数声明如下:

def save_checkpoint(save_obj, ckpt_file_name, integrated_save=True,
                    async_save=False, append_dict=None, enc_key=None, enc_mode="AES-GCM")

其中必填的参数有:save_objckpt_file_name

下面通过具体示例来说明如何使用每个参数。

save_objckpt_file_name参数

save_obj:可以传入一个 Cell类对象或一个list。 ckpt_file_name:string类型,表示保存checkpoint文件的名称。

from mindspore import save_checkpoint, Tensor
from mindspore import dtype as mstype
  1. 传入Cell对象

    net = LeNet()
    save_checkpoint(net, "lenet.ckpt")
    

    ​执行后就可以把net中的参数保存成lenet.ckpt文件。

  2. 传入list对象

    list格式如下:[{“name”: param_name, “data”: param_data}],它由一组dict对象组成。

    param_name为需要保存对象的名称,param_data为需要保存对象的数据,它为Tensor类型。

    save_list = [{"name": "lr", "data": Tensor(0.01, mstype.float32)}, {"name": "train_epoch", "data": Tensor(20, mstype.int32)}]
    save_checkpoint(save_list, "hyper_param.ckpt")
    

    执行后就可以把save_list保存成hyper_param.ckpt文件。

integrated_save参数

integrated_save:bool类型,表示参数是否合并保存,默认为True。在模型并行场景下,Tensor会被切分到不同卡所运行的程序中。如果integrated_save设置为True,则这些被切分的Tensor会被合并保存到每个checkpoint文件中,这样checkpoint文件保存的就是完整的训练参数。

save_checkpoint(net, "lenet.ckpt", integrated_save=True)

async_save参数

async_save:bool类型,表示是否开启异步保存功能,默认为False。如果设置为True,则会开启多线程执行写checkpoint文件操作,从而可以并行执行训练和保存任务,在训练大规模网络时会节省脚本运行的总时长。

save_checkpoint(net, "lenet.ckpt", async_save=True)

append_dict参数

append_dict:dict类型,表示需要额外保存的信息,例如:

save_dict = {"epoch_num": 2, "lr": 0.01}
save_checkpoint(net, "lenet.ckpt",append_dict=save_dict)

执行后,除了net中的参数,save_dict的信息也会保存在lenet.ckpt中。 目前只支持基础类型的保存,包括int、float、bool等。

导出MindIR格式文件

如果想跨平台或硬件执行推理(如昇腾AI处理器、MindSpore端侧、GPU等),可以通过网络定义和CheckPoint生成MindIR格式模型文件。当前支持基于静态图。导出该格式文件的代码样例如下:

import numpy as np
from mindspore import Tensor, export, load_checkpoint, load_param_into_net

resnet = ResNet50()
# load the parameter into net
load_checkpoint("resnet50-2_32.ckpt", net=resnet)
input = np.random.uniform(0.0, 1.0, size=[32, 3, 224, 224]).astype(np.float32)
export(resnet, Tensor(input), file_name='resnet50-2_32', file_format='MINDIR')

若希望在MindIR中保存模型推理时需要的预处理操作信息,可以将数据集对象传入export接口:

import mindspore.dataset as ds
import mindspore.dataset.vision.c_transforms as C
from mindspore import export, load_checkpoint

def create_dataset_for_renset():
    data_set = ds.ImageFolderDataset(dataset_path)
    mean = [0.485 * 255, 0.456 * 255, 0.406 * 255]
    std = [0.229 * 255, 0.224 * 255, 0.225 * 255]
    data_set = data_set.map(operations=[C.Decode(), C.Resize(256), C.CenterCrop(224),
                            C.Normalize(mean=mean,std=std), C.HWC2CHW()], input_columns="image")

# create Dataset with preprocess operations
de_dataset = create_dataset_for_renset()
# load the parameter into net
resnet = ResNet50()
load_checkpoint("resnet50-2_32.ckpt", net=resnet)
export(resnet, de_dataset, file_name='resnet50-2_32', file_format='MINDIR')
  • inputexport方法的入参,代表网络的输入,如果网络有多个输入,需要一同传进export方法。 例如:export(network, Tensor(input1), Tensor(input2), file_name='network', file_format='MINDIR')

  • input是Tensor类型,则代表网络的输入,注意Tensor的维度需要与网络的输入维度一致;有多个输入时,需要将Tensor组成元组传入。当input是Dataset类型,网络的输入将由Dataset自动推导,且定义在Dataset中的数据预处理行为将同时导出到文件中(仅支持MindIR)。

  • 如果file_name没有包含”.mindir”后缀,系统会为其自动添加”.mindir”后缀。

  • 需要确保数据集对象处于evaluation的状态,即正在使用推理相关的算子,否则可能无法达到预期的结果。

为了避免protobuf的硬件限制,当导出的模型参数大小超过1G时,框架默认会把网络结构和参数分开保存。

  • 网络结构文件的名称以用户指定前缀加_graph.mindir结尾。

  • 同级目录下,会生成一个用户指定前缀加_variables的文件夹,里面存放网络的参数。其中参数大小每超过1T会被分开保存成命名为data_1、data_2、data_3等的多个文件。

以上述代码为例,如果带参数的模型大小超过1G,生成的目录结构如下:

resnet50-2_32_graph.mindir
resnet50-2_32_variables
    data_0

加载时,如果传入的文件名以_graph.mindir结尾,框架会自动查找同级目录下的参数文件。

导出AIR格式文件

如果想在昇腾AI处理器上执行推理,还可以通过网络定义和CheckPoint生成AIR格式模型文件。导出该格式文件的代码样例如下:

import numpy as np
from mindspore import Tensor, export, load_checkpoint, load_param_into_net

resnet = ResNet50()
# load the parameter into net
load_checkpoint("resnet50-2_32.ckpt", net=resnet)
input = np.random.uniform(0.0, 1.0, size=[32, 3, 224, 224]).astype(np.float32)
export(resnet, Tensor(input), file_name='resnet50-2_32', file_format='AIR')

input用来指定导出模型的输入shape以及数据类型。

  • inputexport方法的入参,代表网络的输入,如果网络有多个输入,需要一同传进export方法。 例如:export(network, Tensor(input1), Tensor(input2), file_name='network', file_format='AIR')

  • 如果file_name没有包含”.air”后缀,系统会为其自动添加”.air”后缀。

导出ONNX格式文件

当有了CheckPoint文件后,如果想继续在昇腾AI处理器、GPU、CPU等多种硬件上做推理,需要通过网络和CheckPoint生成对应的ONNX格式模型文件。导出该格式文件的代码样例如下:

import numpy as np
from mindspore import Tensor, export, load_checkpoint, load_param_into_net

resnet = ResNet50()
# load the parameter into net
load_checkpoint("resnet50-2_32.ckpt", net=resnet)
input = np.random.uniform(0.0, 1.0, size=[32, 3, 224, 224]).astype(np.float32)
export(resnet, Tensor(input), file_name='resnet50-2_32', file_format='ONNX')
  • inputexport方法的入参,代表网络的输入,如果网络有多个输入,需要一同传进export方法。 例如:export(network, Tensor(input1), Tensor(input2), file_name='network', file_format='ONNX')

  • 如果file_name没有包含”.onnx”后缀,系统会为其自动添加”.onnx”后缀。

  • 目前ONNX格式导出仅支持ResNet系列、YOLOV3、YOLOV4、BERT网络。