文章目录
1 寒武纪加速平台简介
1.1 加速平台简介
1.1.1 算力硬件
系列 | 推理 | 训练 | 应用类型 | 备注 |
---|---|---|---|---|
MLU220 | ☑️ | ❌ | 边缘端 | INT8 8T算力+8.25W功耗; INT8 16T算力+16.5W;CPU计算能力较弱需要其他主控例如瑞芯微3588 |
MLU270 | ☑️ | ❌ | 服务器端 | 部署服务端的智能分析算法;模型移植硬件平台; |
MLU290 | ☑️ | ☑️ | 训练卡 | 应用在各云厂商、机房和服务中心等,主要用于训练 |
1.1.2 配套软件
主要组成为:
- 驱动
- 运行库插件
- 开源框架
推理部分包括两个开源部分:
EasyDK:基于其运行时库封装的一些常用和简易接口,对我们来说,可能最常用的就是关于离线模型推理部分。相关介绍请参见其官网: https://github.com/Cambricon/easydk
CNStream:基于EasyDK封装的一套应用层库,类似于deepstream和MediaPipe。相关介绍请参见其官网:https://github.com/Cambricon/CNStream
1.2 部署流程简介
寒武纪平台的部署流程有一条主线是将一个原始模型转为一个离线模型。基本流程如下:
- 得到算法的原始模型,如caffe/pytorch/tensorflow等框架的模型。
- 配置对应框架模型的模型转换环境,手动配置/docker。
- 使用对应的框架模型转换环境。
- 进行模型量化、转换得到离线模型。
- 开发支持离线模型的程序应用。
- 调用离线模型进行推理并做其他处理。
1.3 部署环境搭建
推荐系统:ubuntu 18.04,ubuntu 20.04 , ubuntu 22.04
推理模式:一个是cnrt,一个是easydk。easydk是基于cnrt封装的api,大大简化了离线模型推理的开发流程。
主体流程:初始化mlu设备,加载模型,预处理,模型推理,后处理,处理结果。
寒武纪还提供了CNStream程序框架,基于EasyDk开发,以pipeline+observer的方式,提供了一个简单易用的框架,如果有兴趣,请查看其官网 https://github.com/Cambricon/CNStream 。其实要用的是EasyDK+CNRT的这种开发方式,构造一个类似CNStream这样的程序。
1.3.1 安装驱动
两个系列的os
- ubuntu/debian
- centos
下载得到驱动包名:neuware-mlu270-driver-dkms_xxx_all.deb
sudo dpkg -i neuware-mlu270-driver-dkms_xxx_all.deb
查看显卡命令,类似于nvidia-smi:
cnmon
1.3.2 安装CNToolKit
方法1:查看官网
sudo dpkg -i cntoolkit_xxx.deb
sudo apt update
sudo apt-get install cnas cncc cncodec cndev cndrv cnlicense cnpapi cnperf cnrt cnrtc cnstudio
野路子:
- 解压cntoolkit_xxx.deb。
- 找到里面的所有deb文件,选择自己需要的,直接解压安装。
- 注意,野路子在边缘端环境配置的时候、边缘端程序生成的时候有奇效。
配置相关环境变量:
export NEUWARE_HOME="/usr/local/neuware"
export PATH="${NEUWARE_HOME}/bin:${PATH}"
1.3.3 配置模型移植开发环境
寒武纪官方支持3种常见框架的模型移植,分别是caffe/tensorflow/pytorch,官方资料如下:
caffe: https://www.cambricon.com/docs/caffe/index.html
tensorflow: https://www.cambricon.com/docs/tensorflow/user_guide/index.html
pytorch: https://www.cambricon.com/docs/pytorch/index.html
1.4 模型部署
1.4.1 模型转换旧文件格式
# 存在一个模型test.pth(zip格式)
# 存在一个获取的模型网络结构类:TestModel
import torch
model = TestModel()
state_dict = torch.load('test.pth', map_location=torch.device('cpu'))
model.load_state_dict(state_dict, strict=True)
torch.save(model, 'new_test.pth', _use_new_zipfile_serialization=False)
# 得到了旧版本的pth文件。方便pytorch 1.6以下进行加载
1.4.2 量化模型生成
# 存在一个模型new_test.pth(非zip格式)
# 存在一个获取的模型网络结构类:TestModel
import torch
import torch_mlu.core.mlu_quantize as mlu_quantize
model = TestModel()
state_dict = torch.load('new_test.pth', map_location=torch.device('cpu'))
model.load_state_dict(state_dict, False)
mean=[]
std=[]
# 注意此接口,这里不使用firstconv优化,它的作用是将归一化放到第一层去一起加速做,但是有些模型的前处理是不需要这样做的,具体信息,请参考寒武纪官方文档。
net_quantization = mlu_quantize.quantize_dynamic_mlu(model, {'mean':mean, 'std':std, 'firstconv':False}, dtype='int8', gen_quant=True)
torch.save(net_quantization.state_dict(), 'test_quantization.pth')
# 得到了INT8的量化模型文件test_quantization.pth
1.4.3 验证结果
# 存在一个INT8的量化模型文件test_quantization.pth
# 存在一个获取的模型网络结构类:TestModel
import torch_mlu
import torch_mlu.core.mlu_model as ct
import torch_mlu.core.mlu_quantize as mlu_quantize
model = TestModel()
# step 1
net = mlu_quantize.quantize_dynamic_mlu(model)
# step 2
net.load_state_dict(torch.load('test_quantization.pth'))
# 这里是
input_data=torch.randn((1,3,480,480))
# step 3
net_mlu = net.to(ct.mlu_device())
input_mlu = input_data.to(ct.mlu_device())
# step 4
output=net_mlu(input_mlu)
print(output.cpu())
# output的shape是480*480
1.4.4 离线模型生成
# 存在一个INT8的量化模型文件test_quantization.pth
# 存在一个获取的模型网络结构类:TestModel
import torch_mlu
import torch_mlu.core.mlu_model as ct
import torch_mlu.core.mlu_quantize as mlu_quantize
model = TestModel()
# step 1
net = mlu_quantize.quantize_dynamic_mlu(model)
# step 2
net.load_state_dict(torch.load('test_quantization.pth'))
#
input_data=torch.randn((1,3,480,480))
# step 3
net_mlu = net.to(ct.mlu_device())
input_mlu = input_data.to(ct.mlu_device())
# 详细查看文档,一般4
core_number = 4
ct.set_core_number(core_number)
ct.set_core_version('MLU220')
# torch_mlu.core.mlu_model.set_input_format(input_format)
ct.save_as_cambricon('test')
net_trace = torch.jit.trace(net_mlu, input_mlu, check_trace=False)
net_trace(input_mlu)
torch_mlu.core.mlu_model.save_as_cambricon("")
# 最终,我们得到了test.cambricon 和 test.cambricon_twins。test.cambricon_twins是离线模型的说明文件,包含输入数据格式通道等信息,也包含输出相关的信息。
上文的第三四五步其实对应的是
-
EasyInfer下面的ModelLoader模块
-
初始化ModelLoader模块
-
传参给EasyInfer实例
-
为模型在cpu和mlu上申请相关的内存空间。在EasyDk中有对应的接口直接完成内存申请
-
图像数据预处理,到图像数据类型转换,再到图像数据输入到mlu内存
-
推理准备参数
-
开始推理
-
mlu内存中拷贝出推理结果到cpu内存,然后进行后处理
-
清理环境
是
-
EasyInfer下面的ModelLoader模块
-
初始化ModelLoader模块
-
传参给EasyInfer实例
-
为模型在cpu和mlu上申请相关的内存空间。在EasyDk中有对应的接口直接完成内存申请
-
图像数据预处理,到图像数据类型转换,再到图像数据输入到mlu内存
-
推理准备参数
-
开始推理
-
mlu内存中拷贝出推理结果到cpu内存,然后进行后处理
-
清理环境