当前位置:   article > 正文

Vitis AI 基本操作+模型检查(inspector)用法详解_“nndct”

“nndct”

目录

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 版本信息:

  1. Python 3.7.12
  2. PyTorch 1.10.1
  3. torchvision 0.11.2
  1. import torch
  2. from torchvision.models import resnet18
  3. from pytorch_nndct.apis import Inspector
  4. from IPython.display import Image

功能解释: 

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

2.2 创建 Inspector

  1. target = "DPUCZDX8G_ISA1_B4096"
  2. inspector = Inspector(target)
  3. #---
  4. #输出
  5. #---
  6. [VAIQ_NOTE]: =>Inspector is initialized successfully with target:
  7. name: DPUCZDX8G_ISA1_B4096
  8. type: DPUCZDX8G
  9. isa_version: 1

 该方法来自于类:

  1. # <Vitis-AI-2.5/src/Vitis-AI-Quantizer/vai_q_pytorch/pytorch_binding/pytorch_nndct/apis.py>
  2. ---
  3. class Inspector(object):
  4. def __init__(self, name_or_fingerprint: str):

两种创建方法:

  1. inspector = Inspector("0X101000016010407") # by target fingerprint
  2. # or
  3. inspector = Inspector("DPUCZDX8G_ISA1_B4096") # by target name

目标指纹(target fingerprint)是 Vitis AI 框架中用于表征不同 DPU 目标的唯一标识符。它由1个字节表示 DPU 类型、1个字节表示 ISA 版本、6个字节表示具体配置组成(feature code)。

2.3 下载模型

  1. model = resnet18(pretrained=True)
  2. model.eval()

当使用 pretrained=True 参数时,模型会自动从网络上下载预训练的权重并将其加载到模型中。 下载完毕,显示如下内容:

  1. Downloading: "https://download.pytorch.org/models/resnet18-f37072fd.pth" to /home/vitis-ai-user/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth
  2. 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 检查模型

  1. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  2. dummy_input = torch.randn(1, 3, 224, 224)
  3. inspector.inspect(model, (dummy_input,), device=device, output_dir="inspect", image_format="png")
  • device:指定模型在检查过程中的计算设备。

检查完毕,输出:

  1. [VAIQ_NOTE]: =>Start to inspect model...
  2. [VAIQ_NOTE]: =>Quant Module is in 'cpu'.
  3. [VAIQ_NOTE]: =>Parsing ResNet...
  4. [VAIQ_NOTE]: Start to trace model...
  5. [VAIQ_NOTE]: Finish tracing.
  6. [VAIQ_NOTE]: Processing ops...
  7. ██████████████████████████████████████████████████| 71/71 [00:00<00:00, 750.15it/s, OpInfo: name = return_0, type = Return]
  8. [VAIQ_NOTE]: =>Doing weights equalization...
  9. [VAIQ_NOTE]: =>Quantizable module is generated.(inspect/ResNet.py)
  10. [VAIQ_NOTE]: All the operators are assigned to the DPU(see more details in 'inspect/inspect_DPUCZDX8G_ISA1_B4096.txt')
  11. [VAIQ_NOTE]: Dot image is generated.(inspect/inspect_DPUCZDX8G_ISA1_B4096.png)
  12. [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

  1. -rw-r--r-- 1 xx xx 17607 inspect_DPUCZDX8G_ISA1_B4096.gv
  2. -rw-r--r-- 1 xx xx 1289898 inspect_DPUCZDX8G_ISA1_B4096.png
  3. -rw-r--r-- 1 xx xx 299103 inspect_DPUCZDX8G_ISA1_B4096.txt
  4. -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:

  1. Pytorch: conv:[1, 64, 1, 1] -> reshape(shape=(1, -1):[1, 64]
  2. =>
  3. Xmodel: conv:[1, 1, 1, 64] -> permute(order=(0, 3, 1, 2)):[1, 64, 1, 1] -> reshape(shape=(1, -1):[1, 64]

在原始浮点模型中插入一个 permute:

  1. Pytorch: conv:[1, 64, 1, 1] -> permute(order=(0, 2, 3, 1)):[1, 1, 1, 64] -> reshape(shape=(1, -1):[1, 64]
  2. =>
  3. Xmodel: conv:[1, 1, 1, 64] -> reshape(shape=(1, -1):[1, 64]

量化器插入的 permute 可以通过在浮点模型中插入一个 permute 来取消。

修改模型后,输出形状和数据内存布局与之前相同。

示例 2:

  1. Pytorch: conv:[1, 3, 4, 4] -> reshape(shape=(1, -1):[1, 48]
  2. =>
  3. Xmodel: conv:[1, 4, 4, 3] -> permute(order=(0, 3, 1, 2)):[1, 3, 4, 4] -> reshape(shape=(1, -1):[1, 48]

在原始浮点模型中插入一个 permute:

  1. Pytorch: conv:[1, 3, 4, 4] -> permute(order=(0, 2, 3, 1)):[1, 4, 4, 3] -> reshape(shape=(1, -1):[1, 48]
  2. =>
  3. Xmodel: conv:[1, 4, 4, 3] -> reshape(shape=(1, -1):[1, 48]

量化器插入的 permute 不能通过在浮点模型中插入一个 permute 来取消。

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

2.5.3 Target Info

  1. ================================================================================================================================================================
  2. target info:
  3. ================================================================================================================================================================
  4. name: "DPUCZDX8G_ISA1_B4096"
  5. type: "DPUCZDX8G" - DPU的类型
  6. isa_version: 1 - 指令集架构版本
  7. feature_code: 369165319 - 特性代码
  8. ---------------------------------------------------------------------
  9. - 描述了不同类型的内存组及其配置。
  10. - VB0 和 VB1: 虚拟内存组,每组有8个内存块,每块宽度为16,深度为2048
  11. - CONVW: 参数内存组,有16个内存块,每块宽度为16,深度为2048
  12. - DWCONVW 和 BIAS: 参数内存组,各有1个内存块,每块宽度为16,深度为2048
  13. bank_group {
  14. name: "VB0"
  15. bank_num: 8
  16. bank_width: 16
  17. bank_depth: 2048
  18. type: "Virtual"
  19. }
  20. bank_group {
  21. name: "VB1"
  22. base_id: 8
  23. bank_num: 8
  24. bank_width: 16
  25. bank_depth: 2048
  26. type: "Virtual"
  27. }
  28. bank_group {
  29. name: "CONVW"
  30. base_id: 16
  31. bank_num: 16
  32. bank_width: 16
  33. bank_depth: 2048
  34. type: "Param"
  35. }
  36. bank_group {
  37. name: "DWCONVW"
  38. base_id: 32
  39. bank_num: 1
  40. bank_width: 16
  41. bank_depth: 2048
  42. type: "Param"
  43. }
  44. bank_group {
  45. name: "BIAS"
  46. base_id: 33
  47. bank_num: 1
  48. bank_width: 16
  49. bank_depth: 2048
  50. type: "Param"
  51. }
  52. ---------------------------------------------------------------------
  53. load_engine { - 加载引擎的配置
  54. channel_parallel: 16
  55. output_bank: "VB0"
  56. output_bank: "VB1"
  57. }
  58. save_engine { - 保存引擎的配置
  59. channel_parallel: 16
  60. input_bank: "VB0"
  61. input_bank: "VB1"
  62. }
  63. conv_engine { - 卷积引擎的配置
  64. input_channel_parallel: 16
  65. output_channel_parallel: 16
  66. pixel_parallel: 8
  67. input_bank: "VB0"
  68. input_bank: "VB1"
  69. weight_bank: "CONVW" - 权重内存组
  70. bias_bank: "BIAS" - 偏置内存组
  71. channel_augmentation { - 通道增强
  72. channel_num: 32
  73. }
  74. nonlinear { - 非线性激活函数类型
  75. nonlinear_type: relu
  76. nonlinear_type: leaky_relu
  77. nonlinear_type: relu_six
  78. }
  79. output_bank: "VB0"
  80. output_bank: "VB1"
  81. conv_limit { - 卷积限制
  82. kernel_size: "1-16"
  83. stride: "1-8"
  84. stride_out_h: "1-4"
  85. }
  86. }
  87. eltwise_engine { - 逐元素操作引擎
  88. channel_parallel: 16
  89. pixel_parallel: 4
  90. input_bank: "VB0"
  91. input_bank: "VB1"
  92. output_bank: "VB0"
  93. output_bank: "VB1"
  94. nonlinear {
  95. nonlinear_type: relu
  96. }
  97. elew_type: add
  98. elew_type: mult
  99. }
  100. alu_engine { - 算术逻辑单元(ALU)引擎
  101. channel_parallel: 16
  102. pixel_parallel: 4
  103. input_bank: "VB0"
  104. input_bank: "VB1"
  105. output_bank: "VB0"
  106. output_bank: "VB1"
  107. weight_bank: "DWCONVW"
  108. bias_bank: "BIAS"
  109. alu_type: dwconv
  110. alu_type: prelu
  111. alu_type: avg_pool
  112. alu_type: max_pool
  113. alu_type: leaky_relu
  114. alu_type: max_reduce
  115. alu_type: dwconv_no_bias
  116. alu_type: hsigmoid
  117. alu_type: w16b0
  118. nonlinear {
  119. nonlinear_type: relu
  120. nonlinear_type: relu_six
  121. }
  122. alu_limit { - ALU操作限制
  123. kernel_size: "1-256"
  124. stride: "1-256"
  125. stride_out_h: "1-4"
  126. }
  127. pad_limit { - 填充限制
  128. pad_left: "0-15"
  129. pad_right: "0-255"
  130. pad_top: "0-15"
  131. pad_bottom: "0-255"
  132. }
  133. }

2.5.4 Inspection Summary

如果一切顺利:

All the operators are assigned to the DPU.

2.5.5 Node Details

  1. ================================================================================================================================================================
  2. node name: ResNet::ResNet/Sequential[layer1]/BasicBlock[0]/Conv2d[conv1]/input.9
  3. input nodes: ['ResNet::ResNet/MaxPool2d[maxpool]/input.7']
  4. output nodes: ['ResNet::ResNet/Sequential[layer1]/BasicBlock[0]/ReLU[relu]/input.13']
  5. op type: conv2d
  6. outputs shape: [(1, 56, 56, 64)]
  7. op attributes:
  8. kernel: [3, 3]
  9. stride: [1, 1]
  10. dilation: [1, 1]
  11. pad_mode: 0
  12. pad: [1, 1, 1, 1]
  13. group: 1
  14. bias_term: True
  15. in_dim: 64
  16. out_dim: 64
  17. assigned device: dpu
  18. source range:
  19. /opt/vitis_ai/conda/envs/vitis-ai-pytorch/lib/python3.7/site-packages/torch/nn/modules/conv.py(443): _conv_forward
  20. /opt/vitis_ai/conda/envs/vitis-ai-pytorch/lib/python3.7/site-packages/torch/nn/modules/conv.py(446): forward
  21. ...

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 中的模型的方法:

  1. import torchvision.models as models
  2. dir(models)
  3. ---
  4. AlexNet
  5. DenseNet
  6. EfficientNet
  7. GoogLeNet
  8. Inception3
  9. MNASNet
  10. MobileNetV2
  11. MobileNetV3
  12. RegNet
  13. ResNet
  14. ShuffleNetV2
  15. SqueezeNet
  16. 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 框架中模型的保存和加载技巧,这对于模型的部署和迁移至关重要。通过这些操作,开发者可以更有效地管理和部署他们的神经网络模型。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号