昇腾 CANN 入门推理全流程 - 超分辨率 (PyTorch, ONNX, AscendCL)
文章目录
开发板到手,当天就将 SD 卡插上进入并狠狠地体验了一把内置的 CANN 案例。但是对着现成的案例沾沾自喜有什么用!我现在就要体验昇腾模型推理全流程!
经过 CANN 训练营的学习,可以肯定的一点是昇腾的推理流程十分易于上手,即便是我这种鲲鹏昇腾小白也可以轻松掌握。
整个流程将分为以下几章节:
另,为开发板插网线时可首先尝试插入下面的端口,因为开启了 DHCP。
模型选择 - MAN 模型
我从研究记录中选择了 MAN 超分辨率模型进行体验。MAN 是一个较轻量的超分辨率模型,精度较好且性能开销少。代码开源较精简,有预训练模型。
我们这次将专注于 MAN-light 模型。我们将代码仓库克隆并下载预训练模型,即可进行下一步。
将 SR 模型转换为中间格式 (MindIR, ONNX)
MAN 模型是基于 PyTorch 框架的模型,所以我们将转换为 ONNX 中间件格式。
载入 PyTorch 模型网络代码
MAN 的模型类型是通过调整网络的参数来实现切换的,参数说明在 options 文件中有定义。
*# ./options/*test_MAN.yml
# network structures
network_g:
- type: MAN*
- scale: 2 #or 3/4*
- n_resblocks: 36 # 5 for MAN-tiny; 24 for MAN-light; 36 for MAN *
- n_resgroups: 1*
- n_feats: 180 # 48 for MAN-tiny; 60 for MAN-light; 180 for MAN *
导入相关程序库并输入我们要的参数,将仓库内的 MAN_arch.py 单独使用生成模型网络,并转换为推理模式。(内部注释掉 BasicSR 库的 Arch 代码)
使用 Python 载入模型
from MAN_arch import MAN
model = MAN(n_resblocks=24, n_resgroups=1, n_feats=60, scale=2) # MAN-light
model.eval() # 不转换精度会下降
Python 会打印出模型网络:
MAN(
- (sub_mean): MeanShift(3, 3, kernel_size=(1, 1), stride=(1, 1))*
- (head): Conv2d(3, 60, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))*
- (body): ModuleList(*
……
小贴士:由于不是训练,用于生成数据集以及优化器不需要生成,只关注模型网络,简化代码。
在 GitHub 仓库下载预训练模型,在这使用 PyTorch 的方法 load_state_dict 载入权重。
model.load_state_dict(torch.load("MAN-Light-x2.pth"), strict=True)
打印模型权重的载入情况。
for param_tensor in model.state_dict():`
print(param_tensor, "\t", model.state_dict()[param_tensor].size())
Model’s state_dict:
sub_mean.weight ** ** torch.Size([3, 3, 1, 1])
sub_mean.bias ** ** torch.Size([3])
……
生成一个测试张量,这个张量需要和之前训练模型的张量结构相等,你可以通过调试来获取以前的张量结构,一般是 NCHW 格式。MAN 超分辨率模型只对 H, W 参数不敏感。
testTensor = torch.tensor([[[[1.]],[[1.]],[[1.]]]])
# 或者使用 touch.ones 函数,两个相等
testTensor = torch.ones((1, 3, 1, 1), dtype=torch.float32)
小贴士:这里需要注意,张量数据类型 (dtype) 要与模型中偏置 (bias) 的数据类型一致。
使用一行代码将构建好的 PyTorch 模型导出至 ONNX,注意这里要使用 dynamic_axes 使输入图片大小任意。
torch.onnx.export(
model,
testTensor,
".\\test_onnx1.onnx",
verbose=False,
input_names=["image_in"],
output_names=["image_out"],
dynamic_axes={
"image_in": {0: 'batch_size', 2 : 'in_width', 3: 'in_height'},
"image_out": {0: 'batch_size', 2: 'out_width', 3:'out_height'}}
)
导出完成,可以使用 Netron 可视化模型,真炫酷。
模型输入节点的名字不一定是 image_in ,可以任意设置。
至此我们就已经转换为了 ONNX 格式,让我们来到转换为昇腾模型的准备阶段。
将中间格式模型转换为昇腾 OM 模型
准备阶段
开始查阅昇腾文档所需的资料。首先我们需要将动态输入在转换为 OM 模型时实现。
设置输入图片的动态分辨率:适用于执行推理时,每次处理图片宽和高不固定的场景。
将解析的shape中的H和W设置为-1,会在shape下方出现Dynamic Image Size参数。在其中的编辑框中输入具体的动态分辨率参数,最少输入两组,每一组参数通过英文分号分隔,组内参数使用英文逗号分隔。最多支持100档配置,例如输入112,112;224,224。
来自 昇腾文档
为了加快模型转换速度,我们后续也会对图片做补边预处理,使一些长宽稍微偏离输入尺寸的图片也能正确进行推理。
我们也需要实现 MAN 模型在训练时的预处理方法。MAN 模型是用 BasicSR 库进行训练的,这是一个通用的超分辨率训练库,图片的预处理会定义在 util 文件夹内,可以从数据的加载方法中看到数据处理方法。
*# From *paired_image_dataset.py
# Load gt and lq images. Dimension order: HWC; channel order: BGR;
# image range: [0, 1], float32.
# BGR to RGB, HWC to CHW, numpy to tensor
看到了颜色通道排列方法是 R, G, B,而最终的张量排布是 NCHW,颜色需要均一化 (0~1),数据精度为32位浮点数,以上就是预处理方式。
还记得开头提到的 CANN 示例吗?里面有我们可以复用的轮子—— ACL 推理流程代码。所以我们只需要在示例的基础上修改部分操作,即可成功运行。
python/level2_simple_inference/1_classification/resnet50_imagenet_classification/src/acl_net.py · Ascend/samples - 码云 - 开源中国 (gitee.com)
上述的是 ResNet-50 分类网络模型,里面有完整的 AscendCL 流程。我们将修改:
- 图片预处理函数
- 显示 / 保存图片函数
- 主函数
对于昇腾设备来说它们要做的流程并没有变,只是我们需要使用 PIL 进行 CPU 方式的图片补边,推理后再裁边。
转换流程
因为内存需求,我们将直接使用非昇腾设备 Ubuntu 系统完成转换。转换之前需要安装 CANN 环境。
安装步骤(Ubuntu 18.04)-安装依赖-安装开发环境-软件安装 (命令行)-环境准备-6.3.RC2.alpha003-CANN社区版-文档首页-昇腾社区 (hiascend.com)
首先使用命令迁移,命令按照官方文档来使用
atc --model=./MAN_light_x2.onnx \
--framework=5 \
--input_shape="image_in:1,3,-1,-1" \
--dynamic_image_size="416,416;832,832" \
--output=$HOME/Model_Convert/MAN/MAN-light_x2 \
--soc_version=Ascend310B1
一行命令中的参数:
- 模型路径
- 模型类型(ONNX)
- 输入尺寸(-1为预设动态分辨率)
- 预设动态分辨率
- 输出路径
- 目标芯片
设置的预设越多,读条越久。但等到成功的那一刻还是很开心的。
我们现在已经有了昇腾 OM 模型,可以用于推理了。简化流程,我们下面使用静态分辨率模型。
使用 AscendCL 进行推理
改写示例
启动 A2 开发板,启动 Jupyter Lab 样例,找到“03-resnet”示例,打开即可看到代码。
但很多代码是可以复用的,我们只需修改以下部分:
图片预处理:
def preprocess_img(input_path, target_shape_list:tuple):
"""图片预处理"""
input_path = os.path.abspath(input_path)
with Image.open(input_path) as image_file:
current_image_size = image_file.size
padding_image = image_file
padding_image.show()
# 归一化
img = np.array(padding_image,dtype=np.float32) / 255
# NCHW
img = np.expand_dims(np.transpose(img, (2,0,1)), axis=0)
result = np.frombuffer(img.tobytes(), np.float32)
return result, current_image_size
打印推理结果:
def _print_result(self, result):
"""打印推理结果
在 ResNet50 样例内这里是将 NumPy 转换为置信度
对于超分辨率直接 NumPy 数组转成图像输出好了"""
# NumPy 结果转 PIL 图片,NCHW -> HWC
for i in result:
i = np.transpose(i[0][0:3], (1,2,0))
i = np.clip(i, 0., 1.) * 255
i = i.astype(np.uint8)
i = np.clip(i,0,255)
i = Image.fromarray(i,"RGB")
i.show()
主函数:
def main():
device = 0
model_path = 'MAN-light_x2_200x200.om'
images_path = './data'
targetList = ((200, 200),(300,300))
net = Net(device, model_path, targetList[0])
# 从文件夹读取图片进行流程
images_list = [os.path.join(images_path, img)
for img in os.listdir(images_path)
if os.path.splitext(img)[1] in IMG_EXT]
for image in images_list:
print("images:{}".format(image))
img, picSize = preprocess_img(image, targetList[0])
pred_dict = net.run([img])
print("*****run finish******")
net.release_resource()
以及适配预设的动态分辨率。
修改完毕,点击开始运行,我们使用 Set5 数据集进行测试。
可以看到成功推理出大图片~
小贴士:如果对 AscendCL 代码全流程较难理解,可转而使用示例 “Unet++”,这个示例将 ACL 封装起来成 acllite_util ,大大简化步骤,更易上手。
(两行代码即可)
总结
简要说明流程:
-
从研究记录中选择一个模型作为实验(首选 SR 超分辨率模型)
- MAN 轻量
- 有预训练模型
- 开源
-
将 SR 模型转换为中间格式 (MindIR, ONNX)
- PyTorch 转换为 ONNX
- ONNX 要打开动态输入
-
将中间格式模型转换为昇腾 OM 模型
- OM 模型需要预设动态分辨率
- 动态分辨率越多转换越久
-
使用 AscendCL 进行推理
- 改写了昇腾原有示例
整个自身的体验流程就告一段落了。其中最有意思的肯定是平台的推理通过 ATC 将模型网络编译,大大缩短推理时间,算力开销大幅降低,才发现在模型边缘计算推理场景中性能需求可以压缩的如此低。将模型转换为昇腾 OM 模型所用的时间能接受,搭配上开发板的 GPIO 接口则有机会作为物联网的中枢。我自身也打算使用昇腾设备对开发模型进行推理测试,充分验证网络的实际应用性能;以及将昇腾开发板带到户外去,使用真实场景进行推理,所以求求官方赶快出一个外壳吧,把 PCB 螺丝孔设计图公开一下也可以啊(笑)。
感谢大家的观看,未来还会带来其他的进阶操作流程!
环境配置
昇腾环境
- Atlas 200I DK A2 开发者套件
- Ubuntu 20.04 LTS (aarch64)
- CANN 6.3.RC1.alpha001
开发环境
- Windows 11 Home 22H2
- WSL 2 (Ubuntu 20.04)
链接
安装须知-软件安装 (命令行)-环境准备-6.3.RC2.alpha003-CANN社区版-文档首页-昇腾社区 (hiascend.com)
学习向导-ATC模型转换-推理应用开发-6.3.RC2.alpha003-CANN社区版-文档首页-昇腾社区 (hiascend.com)
导出ONNX模型-保存与导出模型-PyTorch 网络模型迁移和训练-模型开发(PyTorch)-6.3.RC1-CANN商用版-文档首页-昇腾社区 (hiascend.com)
samples: CANN Samples (gitee.com)