Vitis AI 基本操作(inspector用法详解+输出文件分析+保存模型/权重)

目录

1. 简介

2. 代码详解

2.1 导入所需的库

2.2 创建 Inspector

2.3 下载模型

2.4 检查模型

2.5 分析输出文件txt

2.5.1 Self Introduction

 2.5.2 Hints

2.5.3 Target Info

2.5.4 Inspection Summary

2.5.5 Node Details

3. 其他函数

3.1 查看 torchvision 中模型

3.2 保存模型

3.2.1 保存模型参数

3.2.2 保存完整模型

3.2.3 加载模型

4. 总结


1. 简介

在《Vitis AI 基本认知(模型校准+量化)》一文中,笔者简单分享了 inspector 的简单用法,本文将深入探究其用法。

inspector 的函数,用来诊断不同器件架构下的神经网络 (NN) 模型。检查器可以基于硬件约束来预测目标器件分配。生成的检查报告可用于指导用户对 NN 模型进行修改或最优化,从而显著降低部署难度并缩短部署时间。

建议在量化浮点模型前对其进行检查。

NNDCT:Neural Network Development and Compiler Tools。

2. 代码详解

2.1 导入所需的库

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

功能解释: 

  • import torch:PyTorch 库,用于深度学习的开源框架,核心功能是张量计算(类似于NumPy)以及深度神经网络的自动求导机制。
  • torchvision.models:建立在 PyTorch 之上的一个库,专门用来处理图像数据。提供了三大主要功能。
    • 一是加载预处理图像数据的工具。
    • 二是常用的图像数据集,如ImageNet、CIFAR10、MNIST等。
    • 三是预训练好的模型,如VGG、ResNet等。
  • Inspector 是 Vitis AI 工具的一部分,用于检查和诊断浮点模型。

2.2 创建 Inspector

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)。

2.3 下载模型

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() 一起使用。

2.4 检查模型

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")
  • device:指定模型在检查过程中的计算设备。

检查完毕,输出:

[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

2.5 分析输出文件txt

-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 文件中的内容。

2.5.1 Self Introduction

在该文件的开始,便有自我介绍,告知本文件所包含的信息内容,翻译后如下:

'inspect.txt' 文件用于显示每个操作在神经网络模型中的所有细节。

字段描述:

  1. target info: 目标设备信息。
  2. inspection summary: 检查的总结报告。
  3. graph name: 表示神经网络模型的图名称。
  4. node name: 图中节点的名称。
  5. input nodes: 节点的父节点。
  6. output nodes: 节点的子节点。
  7. op type: 操作的类型。
  8. output shape: 节点输出张量的形状(数据布局遵循XIR的要求)。
  9. op attributes: 操作的属性(描述与XIR一致)。
  10. assigned device: 执行操作的设备类型。
  11. hardware constraints: 如果操作被分配到CPU,此字段将提供一些关于为什么DPU不支持该操作的提示。
  12. node messages: 此字段将提供有关节点的额外信息(例如,如果量化器需要插入一个permute操作以将数据布局从'NCHW'转换为'NHWC',或从'NCHW'转换为'NHWC'进行部署,这条消息将添加到node_messages中)。
  13. source range: 指向一个源,该源是一个堆栈跟踪,有助于找到源代码中该操作的确切位置。

 2.5.2 Hints

接下来文件展示提示信息,并且举了两个例子。

提示:

由于 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 来取消。

修改模型后,输出数据内存布局发生了变化。

2.5.3 Target Info

================================================================================================================================================================
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"
  }
}

2.5.4 Inspection Summary

如果一切顺利:

All the operators are assigned to the DPU.

2.5.5 Node Details

================================================================================================================================================================
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
...

3. 其他函数

3.1 查看 torchvision 中模型

在 torchvision.models 包中包含了许多图像方面的深度学习任务模型,包括:

  • 图像分类:如 ResNet、VGG、AlexNet 等模型。
  • 语义分割:如 FCN、DeepLab 等模型。
  • 目标检测:如 Faster R-CNN、RetinaNet 等模型。
  • 实例分割:如 Mask R-CNN 等模型。
  • 人物关键点检测:如 Keypoint R-CNN 等模型。
  • 视频分类:如 R3D、MC3 等模型。
  • 光流估计:如 RAFT 等模型。

查看所有 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,它们指的是同一模型的不同配置或使用批量归一化的版本。 

3.2 保存模型

3.2.1 保存模型参数

torch.save(model.state_dict(), "my_model.pth")
  • 这条语句只保存模型的参数(weights 和 biases),即模型的状态字典(state_dict)。
  • state_dict 是一个 Python 字典,包含了模型中所有可学习参数的名称及其对应的张量值。
  • 这种方法适用于只保存模型的参数,而不需要保存模型的结构时。

3.2.2 保存完整模型

torch.save(model, "my_model.pth")
  • 这条语句保存整个模型对象,包括模型的结构和参数。
  • 这种方法适用于需要保存完整的模型,包括其架构和状态,以便在加载时不需要重新定义模型结构。

检查方法:

print(isinstance(model, torch.nn.Module))

如果 model 继承自 torch.nn.Module,应该输出 True。

3.2.3 加载模型

model = torch.load(PATH)

从指定路径 PATH 加载一个用 torch.save 保存的对象。这个对象可以是一个完整的模型、模型的状态字典(state_dict)、张量或其他数据结构。

torch.load 使用 Python 的反序列化机制(pickle)来加载数据,并且可以指定加载到的设备(例如 CPU 或 GPU)。

4. 总结

本文分享了如何使用 Vitis AI 的 Inspector 工具来检查和优化神经网络模型,以适应特定的硬件设备。通过引入 Inspector 的使用方法,从初始化、模型下载、模型检查到输出文件的解析,每一步都详细说明了操作的意义和背后的理由。特别强调了模型在不同硬件配置下的检查重要性,以及如何通过调整模型结构来适应特定的硬件限制。

文章还探讨了 PyTorch 框架中模型的保存和加载技巧,这对于模型的部署和迁移至关重要。通过这些操作,开发者可以更有效地管理和部署他们的神经网络模型。

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值