赞
踩
目录
在《Vitis AI 基本认知(模型校准+量化)》一文中,笔者简单分享了 inspector 的简单用法,本文将深入探究其用法。
inspector 的函数,用来诊断不同器件架构下的神经网络 (NN) 模型。检查器可以基于硬件约束来预测目标器件分配。生成的检查报告可用于指导用户对 NN 模型进行修改或最优化,从而显著降低部署难度并缩短部署时间。
建议在量化浮点模型前对其进行检查。
NNDCT:Neural Network Development and Compiler Tools。
Vitis AI 2.5, Pytorch 版本信息:
- Python 3.7.12
- PyTorch 1.10.1
- torchvision 0.11.2
- import torch
- from torchvision.models import resnet18
- from pytorch_nndct.apis import Inspector
- from IPython.display import Image
功能解释:
- target = "DPUCZDX8G_ISA1_B4096"
- inspector = Inspector(target)
- #---
- #输出
- #---
- [VAIQ_NOTE]: =>Inspector is initialized successfully with target:
- name: DPUCZDX8G_ISA1_B4096
- type: DPUCZDX8G
- isa_version: 1
该方法来自于类:
- # <Vitis-AI-2.5/src/Vitis-AI-Quantizer/vai_q_pytorch/pytorch_binding/pytorch_nndct/apis.py>
- ---
- class Inspector(object):
- def __init__(self, name_or_fingerprint: str):
两种创建方法:
- inspector = Inspector("0X101000016010407") # by target fingerprint
- # or
- inspector = Inspector("DPUCZDX8G_ISA1_B4096") # by target name
目标指纹(target fingerprint)是 Vitis AI 框架中用于表征不同 DPU 目标的唯一标识符。它由1个字节表示 DPU 类型、1个字节表示 ISA 版本、6个字节表示具体配置组成(feature code)。
- model = resnet18(pretrained=True)
- model.eval()
当使用 pretrained=True 参数时,模型会自动从网络上下载预训练的权重并将其加载到模型中。 下载完毕,显示如下内容:
- Downloading: "https://download.pytorch.org/models/resnet18-f37072fd.pth" to /home/vitis-ai-user/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth
- 100% [-------------------------------]44.7M/44.7M [00:06<00:00, 7.62MB/s]
如果使用 model = resnet18(),则不会从网上下载预训练的权重。这种情况下,模型会初始化为随机权重,需要自己进行训练。
训练模式model.train() vs 评估模式model.eval(),这两种模式的主要区别在于某些层(如 Dropout 和 Batch Normalization)的行为不同。
1. Dropout 层:在训练过程中,Dropout 会随机丢弃一部分神经元以防止过拟合。但在评估模式下,Dropout 会被关闭,所有神经元都会被使用。
2. Batch Normalization 层:在评估模式下,Batch Normalization 层会使用在训练过程中计算得到的全局均值和方差,而不是当前 mini-batch 的均值和方差。
3. 梯度计算和权重更新:在评估模式下,模型只进行前向传播,不会计算梯度,也不会更新权重,需要配合 torch.no_grad() 一起使用。
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
- dummy_input = torch.randn(1, 3, 224, 224)
- inspector.inspect(model, (dummy_input,), device=device, output_dir="inspect", image_format="png")
检查完毕,输出:
- [VAIQ_NOTE]: =>Start to inspect model...
- [VAIQ_NOTE]: =>Quant Module is in 'cpu'.
- [VAIQ_NOTE]: =>Parsing ResNet...
- [VAIQ_NOTE]: Start to trace model...
- [VAIQ_NOTE]: Finish tracing.
- [VAIQ_NOTE]: Processing ops...
- ██████████████████████████████████████████████████| 71/71 [00:00<00:00, 750.15it/s, OpInfo: name = return_0, type = Return]
- [VAIQ_NOTE]: =>Doing weights equalization...
- [VAIQ_NOTE]: =>Quantizable module is generated.(inspect/ResNet.py)
- [VAIQ_NOTE]: All the operators are assigned to the DPU(see more details in 'inspect/inspect_DPUCZDX8G_ISA1_B4096.txt')
- [VAIQ_NOTE]: Dot image is generated.(inspect/inspect_DPUCZDX8G_ISA1_B4096.png)
- [VAIQ_NOTE]: =>Finish inspecting.
重点关注:All the operators are assigned to the DPU(see more details in 'inspect/inspect_DPUCZDX8G_ISA1_B4096.txt'),所有操作都分配给了DPU。
- -rw-r--r-- 1 xx xx 17607 inspect_DPUCZDX8G_ISA1_B4096.gv
- -rw-r--r-- 1 xx xx 1289898 inspect_DPUCZDX8G_ISA1_B4096.png
- -rw-r--r-- 1 xx xx 299103 inspect_DPUCZDX8G_ISA1_B4096.txt
- -rw-r--r-- 1 xx xx 11791 ResNet.py
我们重点分析 inspect_DPUCZDX8G_ISA1_B4096.txt 文件中的内容。
在该文件的开始,便有自我介绍,告知本文件所包含的信息内容,翻译后如下:
'inspect.txt' 文件用于显示每个操作在神经网络模型中的所有细节。
字段描述:
接下来文件展示提示信息,并且举了两个例子。
提示:
由于 Pytorch ('NCHW') 和 XIR ('NHWC') 之间的数据布局差异,如果量化器插入了一些 permute(来自节点消息),这些 permute 可能会阻止整个模型被部署到目标设备。某些情况下,可以通过在原始浮点模型中插入一个 permute 来取消自动插入的 permute,有时则不能。
以下两个示例用于说明这个问题:
示例 1:
- Pytorch: conv:[1, 64, 1, 1] -> reshape(shape=(1, -1):[1, 64]
- =>
- Xmodel: conv:[1, 1, 1, 64] -> permute(order=(0, 3, 1, 2)):[1, 64, 1, 1] -> reshape(shape=(1, -1):[1, 64]
在原始浮点模型中插入一个 permute:
- Pytorch: conv:[1, 64, 1, 1] -> permute(order=(0, 2, 3, 1)):[1, 1, 1, 64] -> reshape(shape=(1, -1):[1, 64]
- =>
- Xmodel: conv:[1, 1, 1, 64] -> reshape(shape=(1, -1):[1, 64]
量化器插入的 permute 可以通过在浮点模型中插入一个 permute 来取消。
修改模型后,输出形状和数据内存布局与之前相同。
示例 2:
- Pytorch: conv:[1, 3, 4, 4] -> reshape(shape=(1, -1):[1, 48]
- =>
- Xmodel: conv:[1, 4, 4, 3] -> permute(order=(0, 3, 1, 2)):[1, 3, 4, 4] -> reshape(shape=(1, -1):[1, 48]
在原始浮点模型中插入一个 permute:
- Pytorch: conv:[1, 3, 4, 4] -> permute(order=(0, 2, 3, 1)):[1, 4, 4, 3] -> reshape(shape=(1, -1):[1, 48]
- =>
- Xmodel: conv:[1, 4, 4, 3] -> reshape(shape=(1, -1):[1, 48]
量化器插入的 permute 不能通过在浮点模型中插入一个 permute 来取消。
修改模型后,输出数据内存布局发生了变化。
- ================================================================================================================================================================
- target info:
- ================================================================================================================================================================
- name: "DPUCZDX8G_ISA1_B4096"
- type: "DPUCZDX8G" - DPU的类型
- isa_version: 1 - 指令集架构版本
- feature_code: 369165319 - 特性代码
-
- ---------------------------------------------------------------------
- - 描述了不同类型的内存组及其配置。
- - VB0 和 VB1: 虚拟内存组,每组有8个内存块,每块宽度为16,深度为2048。
- - CONVW: 参数内存组,有16个内存块,每块宽度为16,深度为2048。
- - DWCONVW 和 BIAS: 参数内存组,各有1个内存块,每块宽度为16,深度为2048。
-
- bank_group {
- name: "VB0"
- bank_num: 8
- bank_width: 16
- bank_depth: 2048
- type: "Virtual"
- }
- bank_group {
- name: "VB1"
- base_id: 8
- bank_num: 8
- bank_width: 16
- bank_depth: 2048
- type: "Virtual"
- }
- bank_group {
- name: "CONVW"
- base_id: 16
- bank_num: 16
- bank_width: 16
- bank_depth: 2048
- type: "Param"
- }
- bank_group {
- name: "DWCONVW"
- base_id: 32
- bank_num: 1
- bank_width: 16
- bank_depth: 2048
- type: "Param"
- }
- bank_group {
- name: "BIAS"
- base_id: 33
- bank_num: 1
- bank_width: 16
- bank_depth: 2048
- type: "Param"
- }
- ---------------------------------------------------------------------
- load_engine { - 加载引擎的配置
- channel_parallel: 16
- output_bank: "VB0"
- output_bank: "VB1"
- }
- save_engine { - 保存引擎的配置
- channel_parallel: 16
- input_bank: "VB0"
- input_bank: "VB1"
- }
- conv_engine { - 卷积引擎的配置
- input_channel_parallel: 16
- output_channel_parallel: 16
- pixel_parallel: 8
- input_bank: "VB0"
- input_bank: "VB1"
- weight_bank: "CONVW" - 权重内存组
- bias_bank: "BIAS" - 偏置内存组
- channel_augmentation { - 通道增强
- channel_num: 32
- }
- nonlinear { - 非线性激活函数类型
- nonlinear_type: relu
- nonlinear_type: leaky_relu
- nonlinear_type: relu_six
- }
- output_bank: "VB0"
- output_bank: "VB1"
- conv_limit { - 卷积限制
- kernel_size: "1-16"
- stride: "1-8"
- stride_out_h: "1-4"
- }
- }
- eltwise_engine { - 逐元素操作引擎
- channel_parallel: 16
- pixel_parallel: 4
- input_bank: "VB0"
- input_bank: "VB1"
- output_bank: "VB0"
- output_bank: "VB1"
- nonlinear {
- nonlinear_type: relu
- }
- elew_type: add
- elew_type: mult
- }
- alu_engine { - 算术逻辑单元(ALU)引擎
- channel_parallel: 16
- pixel_parallel: 4
- input_bank: "VB0"
- input_bank: "VB1"
- output_bank: "VB0"
- output_bank: "VB1"
- weight_bank: "DWCONVW"
- bias_bank: "BIAS"
- alu_type: dwconv
- alu_type: prelu
- alu_type: avg_pool
- alu_type: max_pool
- alu_type: leaky_relu
- alu_type: max_reduce
- alu_type: dwconv_no_bias
- alu_type: hsigmoid
- alu_type: w16b0
- nonlinear {
- nonlinear_type: relu
- nonlinear_type: relu_six
- }
- alu_limit { - ALU操作限制
- kernel_size: "1-256"
- stride: "1-256"
- stride_out_h: "1-4"
- }
- pad_limit { - 填充限制
- pad_left: "0-15"
- pad_right: "0-255"
- pad_top: "0-15"
- pad_bottom: "0-255"
- }
- }
如果一切顺利:
All the operators are assigned to the DPU.
- ================================================================================================================================================================
- node name: ResNet::ResNet/Sequential[layer1]/BasicBlock[0]/Conv2d[conv1]/input.9
- input nodes: ['ResNet::ResNet/MaxPool2d[maxpool]/input.7']
- output nodes: ['ResNet::ResNet/Sequential[layer1]/BasicBlock[0]/ReLU[relu]/input.13']
- op type: conv2d
- outputs shape: [(1, 56, 56, 64)]
- op attributes:
- kernel: [3, 3]
- stride: [1, 1]
- dilation: [1, 1]
- pad_mode: 0
- pad: [1, 1, 1, 1]
- group: 1
- bias_term: True
- in_dim: 64
- out_dim: 64
- assigned device: dpu
- source range:
- /opt/vitis_ai/conda/envs/vitis-ai-pytorch/lib/python3.7/site-packages/torch/nn/modules/conv.py(443): _conv_forward
- /opt/vitis_ai/conda/envs/vitis-ai-pytorch/lib/python3.7/site-packages/torch/nn/modules/conv.py(446): forward
- ...
在 torchvision.models 包中包含了许多图像方面的深度学习任务模型,包括:
查看所有 torchvision.models 中的模型的方法:
- import torchvision.models as models
- dir(models)
- ---
- AlexNet
- DenseNet
- EfficientNet
- GoogLeNet
- Inception3
- MNASNet
- MobileNetV2
- MobileNetV3
- RegNet
- ResNet
- ShuffleNetV2
- SqueezeNet
- VGG
每个模型名称后面可能还有具体的版本号或变种,如 resnet50 或 vgg16_bn,它们指的是同一模型的不同配置或使用批量归一化的版本。
torch.save(model.state_dict(), "my_model.pth")
torch.save(model, "my_model.pth")
检查方法:
print(isinstance(model, torch.nn.Module))
如果 model 继承自 torch.nn.Module,应该输出 True。
model = torch.load(PATH)
从指定路径 PATH 加载一个用 torch.save 保存的对象。这个对象可以是一个完整的模型、模型的状态字典(state_dict)、张量或其他数据结构。
torch.load 使用 Python 的反序列化机制(pickle)来加载数据,并且可以指定加载到的设备(例如 CPU 或 GPU)。
本文分享了如何使用 Vitis AI 的 Inspector 工具来检查和优化神经网络模型,以适应特定的硬件设备。通过引入 Inspector 的使用方法,从初始化、模型下载、模型检查到输出文件的解析,每一步都详细说明了操作的意义和背后的理由。特别强调了模型在不同硬件配置下的检查重要性,以及如何通过调整模型结构来适应特定的硬件限制。
文章还探讨了 PyTorch 框架中模型的保存和加载技巧,这对于模型的部署和迁移至关重要。通过这些操作,开发者可以更有效地管理和部署他们的神经网络模型。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。