
# 基于MindSpore Lite的模型转换
迁移推理业务的整体流程如下：
- [模型准备]
- [转换关键参数准备]
- [模型转换]
- [推理应用适配]
主要通过MindSpore Lite（简称MSLite）进行模型的转换，进一步通过MindSpore Runtime支持昇腾后端的能力来将推理业务运行到昇腾设备上。
 #### 模型准备
MindSpore Lite提供的模型convertor工具可以支持主流的模型格式到MindIR的格式转换，用户需要导出对应的模型文件，推荐导出为ONNX格式。
1. 如何导出ONNX模型
   - PyTorch转ONNX，操作指导请见[此处](https://mmdetection.readthedocs.io/en/v2.22.0/tutorials/pytorch2onnx.html)。
   
   - PyTorch导出ONNX模型样例如下：
     ```
     import torch
     import torchvision
     model = torchvision.models.resnet50(pretrained=True)
     # 保存模型为ONNX格式
     torch.onnx.export(model, torch.randn(1, 3, 224, 224), "resnet50.onnx")
     ```
     
   
   - TensorFlow导出ONNX模型，操作指导请见[此处](https://docs.nvidia.com/deeplearning/tensorrt/quick-start-guide/index.html#export-from-tf)。
    
2. 如何导出PTH模型 PyTorch模型导出时需要包含模型的结构信息，需要利用jit.trace方式完成模型的导出与保存。
   ```
   # If you are instantiating the model with *from_pretrained* you can also easily set the TorchScript flag
   model = BertModel.from_pretrained("bert-base-uncased", torchscript=True)
   # Creating the trace
   traced_model = torch.jit.trace(model, [tokens_tensor, segments_tensors])
   torch.jit.save(traced_model, "traced_bert.pt")
   ```
   
 
 #### 转换关键参数准备
对应的模型转换成MindIR格式，通过后端绑定的编译形式来运行以达到更好的性能（类似静态图的运行模式），所以需要提前准备以下几个重点参数。
1. 输入的inputShape，包含batch信息。
   MSLite涉及到编译优化的过程，不支持完全动态的权重模式，需要在转换时确定对应的inputShape，用于模型的格式的编译与转换，可以在[netron官网](https://netron.app/)进行查看，或者对于模型结构中的输入进行shape的打印，并明确输入的batch。
   一般来说，推理时指定的inputShape和用户的业务及推理场景紧密相关，可以通过原始模型推理脚本或者网络模型进行判断。需要把Notebook中的模型下载到本地后，再放入netron官网中，查看其inputShape。
   如果netron中没有显示inputShape，可能由于使用了动态shape模型导致，请确保使用的是静态shape模型。静态shape模型文件导出方法请参考[模型准备]。
   图1netron中查看inputShape   
   ![](https://support.huaweicloud.com/bestpractice-modelarts/figure/zh-cn_image_0000001754841605.png "点击放大") 
2. 精度选择。 精度选择需要在模型转换阶段进行配置，执行converter_lite命令时通过--configFile参数指定配置文件路径，配置文件通过[precision_mode](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite/mindspore_lite.Context.html)参数指定精度模式。可选的参数有"enforce_fp32"，"preferred_fp32"，"enforce_fp16"，"enforce_origin"或者"preferred_optimal"，默认为"enforce_fp16"。
   ```
   [ascend_context]
   precision_mode= preferred_fp32
   ```
   
 
 #### 模型转换
在ModelArts开发环境中，通过对应的转换预置镜像，直接执行对应的转换过程，对应的转换和评估工具都已经预置了最新版本，详细介绍请见[使用说明](https://www.mindspore.cn/lite/docs/zh-CN/r2.0/use/converter_tool.html)。inputShape查看方法请见[转换关键参数准备]。
```
!converter_lite --modelFile=resnet50.onnx --fmk=ONNX --outputFile=resnet50 --saveType=MINDIR --inputShape="input.1:1,3,224,224" --device=Ascend
```
为了简化用户使用，ModelArts提供了Tailor工具便于用户进行模型转换，具体使用方式参考[Tailor指导文档](https://support.huaweicloud.com/bestpractice-modelarts/modelarts_10_0166.html)。
 #### 推理应用适配
MindSpore Lite提供了JAVA/C++/Python API，进行推理业务的适配，并且在构建模型时，通过上下文的参数来确定运行时的具体配置，例如运行后端的配置等。下文以Python接口为例。
使用MindSpore Lite推理框架执行推理并使用昇腾后端主要包括以下步骤：
- 创建运行上下文：创建[Context](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite/mindspore_lite.Context.html#mindspore_lite.Context)，保存需要的一些基本配置参数，用于指导模型编译和模型执行，在昇腾迁移时需要特别指定target为"Ascend"，以及对应的device_id。
  ```
  context = mslite.Context()
  context.target = ["ascend"]
  context.ascend.device_id = 0
  ```
  
- 模型加载与编译：执行推理之前，需要调用[Model](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite/mindspore_lite.Model.html#mindspore_lite.Model)的[build_from_file](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite/mindspore_lite.Model.html#mindspore_lite.Model.build_from_file)接口进行模型加载和模型编译。模型加载阶段将文件缓存解析成运行时的模型。模型编译阶段会耗费较多时间所以建议Model创建一次，编译一次，多次推理。
  ```
  model = mslite.Model()
  model.build_from_file("./resnet50.mindir", mslite.ModelType.MINDIR, context)
  ```
  
- 输入数据：编译后的模型提供了predict接口用户执行模型推理任务，Inputs输入为List Tensor，这里的Tensor是MSLite的概念，具体的列表长度和tensor类型由转换时的InputShape来确定，由于后端指定了ascend，这些tensor都是在昇腾设备的显存中，用户需要在对应的tensor中填入数据，这些数据也会被搬移到显存中，进一步对于Inputs输入的内容进行处理。
  ```
  data = convert_img(input_image)
  in_data = [np.array(data)]
  inputs = model.get_inputs()
  for i, _input in enumerate(inputs):
  _input.set_data_from_numpy(in_data[i])
  ```
  
- 执行推理：使用[Model](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite/mindspore_lite.Model.html#mindspore_lite.Model)的[predict](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite/mindspore_lite.Model.html#mindspore_lite.Model.predict)进行模型推理，返回值为Outputs，也是List Tensor类型，具体的长度和类别由模型定义，对应的Tensor数据由于指定了ascend后端，Output的内容在显存中，通过tensor的get_data_to_numpy方法来获取，并将数据读取到内存中使用。
  ```
  outputs = model.predict(inputs)
  outputs = [output.get_data_to_numpy() for output in outputs]
  ```
  更多Python接口的高级用法与示例，请参考[Python API](https://www.mindspore.cn/lite/api/zh-CN/r2.0/mindspore_lite.html)。
  
 
