4. 模型编译

Section 2.3, IPU推理方案架构 中提到,IPU推理方案分为模型编译和模型运行时两个阶段。本章将以ONNX、TensorFlow和PyTorch的模型为例,阐述如何通过 PopRT 将不同框架导出的模型转换和编译成 PopEF 格式的二进制文件。

备注

  • 本章中的示例需要Python环境,请确保已经安装 pythonvirtualenv

  • 示例中的命令较长,在PDF格式下拷贝命令请注意被换行符或者分页截断的命令。

备注

本节中将使用 Section 3.6.1, 通过容器安装 中的容器镜像

4.1. ONNX模型

本节将以ONNX模型为例,讲述如何进行模型转换并编译生成PopEF。本节将以 ONNX model zoo 中的 BERT-Squad 模型为例。

创建本示例所需的目录和Python虚拟环境。

$ mkdir -p onnx_bert && \
  cd onnx_bert && \
  virtualenv -p python3 venv && \
  source venv/bin/activate && \
  pip install protobuf==3.19 onnx==1.11 && \
  deactivate

4.1.1. 模型导出

通过 wget 命令下载ONNX model zoo中的 bertsquad-12.onnx 模型。

$ wget https://github.com/onnx/models/raw/87d452a218093f6a60ceb62712ffe1186dce6d64/text/machine_comprehension/bert-squad/model/bertsquad-12.onnx

4.1.2. 选择batch size

在编译阶段需要确定batch size的大小,在PopRT命令行中batch size的确定是通过 input_shape 参数指定的。在指定 input_shape 参数时,需要知道输入的tensor的名称,可以通过ONNX Python API获取。

$ source venv/bin/activate
$ cat > list_input.py << EOF

import onnx
model = onnx.load('bertsquad-12.onnx')
graph = model.graph
print(graph.input)
EOF

$ python list_input.py

$ deactivate

得到如下的输出:

[name: "unique_ids_raw_output___9:0"
type {
   tensor_type {
      elem_type: 7
      shape {
         dim {
            dim_param: "unk__492"
         }
      }
   }
}
, name: "segment_ids:0"
type {
   tensor_type {
      elem_type: 7
      shape {
         dim {
            dim_param: "unk__493"
         }
         dim {
            dim_value: 256
         }
      }
   }
}
, name: "input_mask:0"
type {
   tensor_type {
      elem_type: 7
      shape {
         dim {
            dim_param: "unk__494"
         }
         dim {
            dim_value: 256
         }
      }
   }
}
, name: "input_ids:0"
type {
   tensor_type {
      elem_type: 7
      shape {
         dim {
            dim_param: "unk__495"
         }
         dim {
            dim_value: 256
         }
      }
   }
}
]

可以从中获得输入的参数名称和维度,在此我们使用batch size 16,对应的 input_shape 参数设置如下:

--input_shape input_ids:0=16,256 input_mask:0=16,256 segment_ids:0=16,256 unique_ids_raw_output___9:0=16

4.1.3. 选择精度

ONNX model zoo中的bertsquad-12.onnx模型采用的是FP32的精度,IPU推荐使用FP16的精度。在PopRT中精度是通过参数 --precision fp16 指定的,关于更多参数的信息请参考 PopRT User Guide

--precision fp16

4.1.4. 模型转换和编译

通过以下的命令将 bertsquad-12.onnx 模型转换为使用FP16精度,batch size为16,可以通过PopART运行的ONNX模型,并保存至 bertsquad-12_fp16_bs_16.onnx。同时会将转换出来的模型编译为PopEF格式的二进制文件 executable.popef

如果不指定 --export_popef 参数,则单独执行模型转换的任务。更多模型转换的参数请参考 PopRT 文档。

$ gc-docker -- --rm \
      -v `pwd -P`:/model_conversion \
      -w /model_conversion \
      graphcorecn/poprt-staging:latest \
      --input_model bertsquad-12.onnx     \
      --output_model bertsquad-12_fp16_bs_16.onnx \
      --input_shape input_ids:0=16,256 input_mask:0=16,256 segment_ids:0=16,256 unique_ids_raw_output___9:0=16 \
      --precision fp16 \
      --convert_version 11 \
      --export_popef \
      --ipu_version ipu21

备注

如果在IPU-M2000或Bow-2000的环境中测试, 请使用 --ipu_version ipu2

模型转换成功,在目录中包含以下文件:

$ tree . -L 1
.
├── bertsquad-12.onnx
├── bertsquad-12_fp16_bs_16.onnx
├── executable.popef
├── list_input.py
└── venv

where:

  • bertsquad-12.onnx 是原模型

  • bertsquad-12_fp16_bs_16.onnx 是通过PopRT转换后的模型

  • executable.popef 是编译得到的PopEF文件

备注

本示例完成,请通过 cd .. 回到测试根目录

4.2. TensorFlow模型

本节将以 TensorFlow Hub 中的 ResNet_v2_50 模型为例,讲述如何将TensorFlow模型转换并编译生成PopEF。

创建本示例所需的目录和Python虚拟环境。

$ mkdir -p tensorflow_resnet
$ cd tensorflow_resnet
$ virtualenv -p python3 venv
$ source venv/bin/activate

$ pip install protobuf==3.19 tensorflow==2.6 onnx==1.11 tf2onnx==1.12.1 packaging

$ deactivate

4.2.1. 模型导出

从TensorFlow Hub下载 ResNet_v2_50 模型并解压到指定目录:

$ wget -O resnet_v2_50.tar.gz https://tfhub.dev/google/imagenet/resnet_v2_50/classification/5?tf-hub-format=compressed
$ mkdir resnet_v2_50
$ tar -xf resnet_v2_50.tar.gz -C resnet_v2_50

Section 2.3, IPU推理方案架构 中提到,IPU推理方案使用ONNX模型作为统一的输入模型,需要通过 tf2onnx 工具将其转成ONNX模型。

执行以下命令将SavedModel模型转换为ONNX模型:

$ source venv/bin/activate
$ python -m tf2onnx.convert \
   --saved-model resnet_v2_50 \
   --output resnet_v2_50.onnx \
   --inputs-as-nchw inputs \
   --outputs-as-nchw logits \
   --opset 11

$ deactivate

由于PopART支持的tensor格式是nchw,需要使用 --inputs-as-nchw inputs--outputs-as-nchw logits 将输入和输出tensor从nhwc格式转换成nchw格式。参数 inputslogits 分别为输入和输出的tensor名称,它们可以通过TensorFlow标准工具 saved_model_cli 从模型中读取:

$ source venv/bin/activate
$ python -m tensorflow.python.tools.saved_model_cli \
   show \
   --dir resnet_v2_50/ \
   --all

$ deactivate

输出节选如下:

signature_def['serving_default']:
   The given SavedModel SignatureDef contains the following input(s):
      inputs['inputs'] tensor_info:
         dtype: DT_FLOAT
         shape: (-1, -1, -1, 3)
         name: serving_default_inputs:0
   The given SavedModel SignatureDef contains the following output(s):
      outputs['logits'] tensor_info:
         dtype: DT_FLOAT
         shape: (-1, 1001)
         name: StatefulPartitionedCall:0
   Method name is: tensorflow/serving/predict

其中, inputs['inputs'] tensor_info 描述了该输入名称为 inputs。 同理, outputs['logits'] tensor_info 描述了该输出名称为 logits

4.2.2. 模型转换和编译

这里仅描述使用PopRT进行float16模型编译,如需进行其他优化策略如修改 batch_size 等,请参考 Section 4.1, ONNX模型

由于IPU使用静态编译,需要确定 input_shape 。对于该模型,我们使用 inputs=(4,3,224,224) 进行编译。输入模型为 Section 4.2.1, 模型导出 中获得的 resnet_v2_50.onnx 模型。

$ gc-docker -- --rm \
    -v `pwd -P`:/model_conversion \
    -w /model_conversion \
    graphcorecn/poprt-staging:latest \
    --input_model resnet_v2_50.onnx \
    --precision fp16 \
    --output_model resnet_v2_50_optimized.onnx \
    --input_shape inputs=4,3,224,224 \
    --convert_version 11 \
    --export_popef \
    --ipu_version ipu21

备注

如果在IPU-M2000或Bow-2000环境中测试,请使用 --ipu_version ipu2

模型转换成功,目录中产生转换后的ONNX文件 resnet_v2_50_optimized.onnx,以及编译得到的PopEF文件 file executable.popef

$ tree . -L 1
.
├── executable.popef
├── resnet_v2_50
├── resnet_v2_50.onnx
├── resnet_v2_50.tar.gz
├── resnet_v2_50_optimized.onnx
└── venv

备注

本示例完成,请通过 cd .. 回到测试根目录

4.3. PyTorch模型

本节将以 torchvision 中的 resnet50 为例,讲述如何将PyTorch的模型转换并编译生成PopEF文件。

创建本示例所需的目录和Python虚拟环境。

$ mkdir -p torch_resnet
$ cd torch_resnet
$ virtualenv -p python3 venv
$ source venv/bin/activate
$ pip install torchvision==0.11.2

$ deactivate

4.3.1. 模型导出

首先通过 torchvision 加载 resnet50 模型,确定 batch size 的大小和输入的shape,并将其导出为ONNX文件。

$ source venv/bin/activate
$ cat > export.py << EOF

import torch.onnx
import torchvision.models as models
model = models.resnet50(pretrained=True)
BATCH_SIZE = 4
dummy_input = torch.randn(BATCH_SIZE, 3, 244, 244)
model.eval() # save it to onnx
torch.onnx.export(model, dummy_input, 'resnet50.onnx', opset_version=11)
print('The model saved into resnet50.onnx')
EOF

$ python export.py

$ deactivate

4.3.2. 模型转换和编译

得到的ONNX模型(resnet50.onnx),通过以下的命令进行转换和编译,关于命令中的参数解释,请参考 Section 4.1, ONNX模型 中的内容。

$ gc-docker -- --rm \
    -v `pwd -P`:/model_conversion \
    -w /model_conversion \
    graphcorecn/poprt-staging:latest \
    --input_model resnet50.onnx \
    --precision fp16 \
    --export_popef \
    --ipu_version ipu21

备注

如果在IPU-M2000或Bow-2000环境中测试,请使用 --ipu_version ipu2

命令成功执行,目录中将生成以下文件:

$ tree . -L 1
.
├── executable.popef
├── export.py
├── resnet50.onnx
├── resnet50.onnx.optimized.onnx
└── venv

其中:

  • resnet50.onnx 是原始模型

  • optimized.onnx 是由PopRT转换得到的模型

  • executable.popef 是编译得到的PopEF文件

备注

本示例完成,请通过 cd .. 回到测试根目录