当前位置:   article > 正文

Vitis AI 综合实践(迁移学习+模型量化+DPU部署)_vitis ai dpu

vitis ai dpu

目录

1. 简介

1.1 ResNet18 模型介绍

1.2 迁移学习

2. 模型训练

2.1 选择云平台

2.2 模块导入

2.3 分析模型结构

2.4 修改模型结构

2.4.1 微调训练最后一层(fc)

2.4.2 微调训练所有层

2.5 执行训练

2.6 保存模型

3. 模型编译

3.1 配置 Vitis AI 量化器文件

3.2 执行编译

4. 总结

5. 参考资料

5.1 Featurize 使用技巧

5.2 迁移学习参考


1. 简介

本文分享完整使用 Vitis AI 开发实践过程,包括进行迁移学习,使用量化工具对浮点模型进行量化,并将 xmodel 部署在 DPU 照中。

使用迁移学习的方法,将预训练的 resnet18 模型从原来的 1000 类分类任务,改造为适应自定义的 30 类分类任务。本迁移学习使用同济自豪兄的分类模型。

1.1 ResNet18 模型介绍

ResNet18 是一种基于深度残差网络(ResNet)的卷积神经网络模型,由何凯明等人于2015年提出。ResNet 的核心思想是通过引入残差块(Residual Block),解决了深度网络中的梯度消失和退化问题,使得网络可以更深更有效地学习特征。

ResNet18 是 ResNet 系列中最简单的一个模型,共有18层。

  • 一个7×7的卷积层,输出通道数为64,步幅为2,后接批量归一化(Batch Normalization)和ReLU激活函数。
  • 一个3×3的最大池化层(Max Pooling),步幅为2。
  • 四个由残差块组成的模块,每个模块包含两个或三个残差块,每个残差块由两个3×3的卷积层、批量归一化和ReLU激活函数组成。每个模块的第一个残差块可能会改变输入输出的通道数和步幅,以适应下一个模块。这四个模块的输出通道数分别为64、128、256、512,步幅分别为1、2、2、2。
  • 一个全局平均池化层(Global Average Pooling),将最后一个模块的输出转换为一个一维向量。
  • 一个全连接层(Fully Connected),将一维向量映射到最终的类别数1000类上。

1.2 迁移学习

根据不同的任务和数据集,迁移学习有以下几种常见的方法:

1. 微调网络:这种方法是在预训练模型的基础上,修改最后一层或几层,并且对整个网络进行微调训练。这种方法适用于新数据集和原数据集相似度较高,且新数据集规模较大的情况。

2. 特征提取:这种方法是将预训练模型看作一个特征提取器,冻结除了最后一层以外的所有层,只修改和训练最后一层。这种方法适用于新数据集和原数据集相似度较高,但新数据集规模较小的情况。

3. 模型蒸馏:这种方法是将预训练模型看作一个教师模型,用它来指导一个更小的学生模型,使学生模型能够学习到教师模型的知识。这种方法适用于新数据集和原数据集相似度较低,或者需要减少模型大小和计算量的情况。

2. 模型训练

2.1 选择云平台

本文省去手动搭建 Pytorch 环境,直接通过云平台选择现成的环境:

Featurizeicon-default.png?t=N7T8https://featurize.cn/推荐如下配置:

RTX 3060

PyTorch 1(版本较老的环境,兼容性好)

Docker: v20.10.10

Python: v3.7

PyTorch: v1.10

TensorFlow: v2.7.0

PyTorch 2.0 相较于 PyTorch 1.x 有几个显著的改进和新特性:

  • 性能提升:PyTorch 2.0 引入了 torch.compile,一个可选的编译模式,可以显著提高模型在训练和推理时的性能。
  • 动态形状支持:PyTorch 2.0 支持动态形状,可以处理不同大小的张量而无需重新编译。
  • 分布式训练:改进了对分布式训练的支持,使得在多GPU和多节点环境下的训练更加高效。
  • 新技术栈:引入了如 TorchDynamo、AOTAutograd、PrimTorch 和 TorchInductor 等新技术,这些技术在底层优化了 PyTorch 的操作。

为了保持兼容性,本文使用 PyTorch V1.10 版本。

2.2 模块导入

  1. import time
  2. import os
  3. import numpy as np
  4. from tqdm import tqdm
  5. import torch
  6. import torchvision
  7. import torch.nn as nn
  8. import torch.nn.functional as F
  9. import matplotlib.pyplot as plt
  10. %matplotlib inline
  11. # 忽略红色提示
  12. import warnings
  13. warnings.filterwarnings("ignore")

2.3 分析模型结构

然后导入预训练模型,并查看网络结构:

  1. model = models.resnet18(pretrained=True) # 载入预训练模型
  2. summary(model, (3, 224, 224))
  3. ---以下为执行结果
  4. ----------------------------------------------------------------
  5. Layer (type) Output Shape Param #
  6. ================================================================
  7. Conv2d-1 [-1, 64, 112, 112] 9,408
  8. BatchNorm2d-2 [-1, 64, 112, 112] 128
  9. ReLU-3 [-1, 64, 112, 112] 0
  10. MaxPool2d-4 [-1, 64, 56, 56] 0
  11. Conv2d-5 [-1, 64, 56, 56] 36,864
  12. BatchNorm2d-6 [-1, 64, 56, 56] 128
  13. ReLU-7 [-1, 64, 56, 56] 0
  14. Conv2d-8 [-1, 64, 56, 56] 36,864
  15. BatchNorm2d-9 [-1, 64, 56, 56] 128
  16. ReLU-10 [-1, 64, 56, 56] 0
  17. BasicBlock-11 [-1, 64, 56, 56] 0
  18. Conv2d-12 [-1, 64, 56, 56] 36,864
  19. BatchNorm2d-13 [-1, 64, 56, 56] 128
  20. ReLU-14 [-1, 64, 56, 56] 0
  21. Conv2d-15 [-1, 64, 56, 56] 36,864
  22. BatchNorm2d-16 [-1, 64, 56, 56] 128
  23. ReLU-17 [-1, 64, 56, 56] 0
  24. BasicBlock-18 [-1, 64, 56, 56] 0
  25. Conv2d-19 [-1, 128, 28, 28] 73,728
  26. BatchNorm2d-20 [-1, 128, 28, 28] 256
  27. ReLU-21 [-1, 128, 28, 28] 0
  28. Conv2d-22 [-1, 128, 28, 28] 147,456
  29. BatchNorm2d-23 [-1, 128, 28, 28] 256
  30. Conv2d-24 [-1, 128, 28, 28] 8,192
  31. BatchNorm2d-25 [-1, 128, 28, 28] 256
  32. ReLU-26 [-1, 128, 28, 28] 0
  33. BasicBlock-27 [-1, 128, 28, 28] 0
  34. Conv2d-28 [-1, 128, 28, 28] 147,456
  35. BatchNorm2d-29 [-1, 128, 28, 28] 256
  36. ReLU-30 [-1, 128, 28, 28] 0
  37. Conv2d-31 [-1, 128, 28, 28] 147,456
  38. BatchNorm2d-32 [-1, 128, 28, 28] 256
  39. ReLU-33 [-1, 128, 28, 28] 0
  40. BasicBlock-34 [-1, 128, 28, 28] 0
  41. Conv2d-35 [-1, 256, 14, 14] 294,912
  42. BatchNorm2d-36 [-1, 256, 14, 14] 512
  43. ReLU-37 [-1, 256, 14, 14] 0
  44. Conv2d-38 [-1, 256, 14, 14] 589,824
  45. BatchNorm2d-39 [-1, 256, 14, 14] 512
  46. Conv2d-40 [-1, 256, 14, 14] 32,768
  47. BatchNorm2d-41 [-1, 256, 14, 14] 512
  48. ReLU-42 [-1, 256, 14, 14] 0
  49. BasicBlock-43 [-1, 256, 14, 14] 0
  50. Conv2d-44 [-1, 256, 14, 14] 589,824
  51. BatchNorm2d-45 [-1, 256, 14, 14] 512
  52. ReLU-46 [-1, 256, 14, 14] 0
  53. Conv2d-47 [-1, 256, 14, 14] 589,824
  54. BatchNorm2d-48 [-1, 256, 14, 14] 512
  55. ReLU-49 [-1, 256, 14, 14] 0
  56. BasicBlock-50 [-1, 256, 14, 14] 0
  57. Conv2d-51 [-1, 512, 7, 7] 1,179,648
  58. BatchNorm2d-52 [-1, 512, 7, 7] 1,024
  59. ReLU-53 [-1, 512, 7, 7] 0
  60. Conv2d-54 [-1, 512, 7, 7] 2,359,296
  61. BatchNorm2d-55 [-1, 512, 7, 7] 1,024
  62. Conv2d-56 [-1, 512, 7, 7] 131,072
  63. BatchNorm2d-57 [-1, 512, 7, 7] 1,024
  64. ReLU-58 [-1, 512, 7, 7] 0
  65. BasicBlock-59 [-1, 512, 7, 7] 0
  66. Conv2d-60 [-1, 512, 7, 7] 2,359,296
  67. BatchNorm2d-61 [-1, 512, 7, 7] 1,024
  68. ReLU-62 [-1, 512, 7, 7] 0
  69. Conv2d-63 [-1, 512, 7, 7] 2,359,296
  70. BatchNorm2d-64 [-1, 512, 7, 7] 1,024
  71. ReLU-65 [-1, 512, 7, 7] 0
  72. BasicBlock-66 [-1, 512, 7, 7] 0
  73. AdaptiveAvgPool2d-67 [-1, 512, 1, 1] 0
  74. Linear-68 [-1, 1000] 513,000
  75. ================================================================
  76. Total params: 11,689,512
  77. Trainable params: 11,689,512
  78. Non-trainable params: 0
  79. ----------------------------------------------------------------
  80. Input size (MB): 0.57
  81. Forward/backward pass size (MB): 62.79
  82. Params size (MB): 44.59
  83. Estimated Total Size (MB): 107.96
  84. ----------------------------------------------------------------

可以原始看到最后一层有1000个特征输出,对应1000分类。我们要做的,就是使用特征提取方法,修改最后一层(FC),实现一个30分类的特征输出。

2.4 修改模型结构

2.4.1 微调训练最后一层(fc)

查看当前 fc 层状态:

  1. print(model.fc)
  2. ---
  3. Linear(in_features=512, out_features=1000, bias=True)

修改全链接层,输入特征数(in_features)保持不变,输出特征数(out_features)设置为30:

model.fc = torch.nn.Linear(model.fc.in_features, 30)

查看修改后 fc 层状态: 

  1. print(model.fc)
  2. ---
  3. Linear(in_features=512, out_features=30, bias=True)

只微调训练最后一层全连接层的参数,其它层冻结 

optimizer = optim.Adam(model.fc.parameters())

2.4.2 微调训练所有层

optimizer = optim.Adam(model.parameters())

2.5 执行训练

配置优化器,只微调输出层(FC),然后执行训练:

  1. # 遍历每个 EPOCH
  2. for epoch in tqdm(range(EPOCHS)):
  3. model.train()
  4. for images, labels in train_loader: # 获取训练集的一个 batch,包含数据和标注
  5. images = images.to(device)
  6. labels = labels.to(device)
  7. outputs = model(images) # 前向预测,获得当前 batch 的预测结果
  8. loss = criterion(outputs, labels) # 比较预测结果和标注,计算当前 batch 的交叉熵损失函数
  9. optimizer.zero_grad()
  10. loss.backward() # 损失函数对神经网络权重反向传播求梯度
  11. optimizer.step() # 优化更新神经网络权重
  12. ---以下为执行结果
  13. 100%|██████████| 20/20 [03:04<00:00, 9.24s/it]

在测试集的准确度为:85.900 %

注:本文不详解如何构建数据集加载器,以及测试部分相关代码,只保留关键代码以演示使用迁移学习过程,需要读者自行补齐机器学习相关知识。

2.6 保存模型

导出迁移学习后的结果模型:

torch.save(model, 'resnet18_out30.pth')

将在当前工作目录下,生成 resnet18_out30.pth 文件。

3. 模型编译

3.1 配置 Vitis AI 量化器文件

默认的量化配置如下:

  1. "convert_relu6_to_relu": 关闭,
  2. "include_cle": 启用,
  3. "keep_first_last_layer_accuracy": 关闭,
  4. "keep_add_layer_accuracy": 关闭,
  5. "include_bias_corr": 开,
  6. "target_device": "DPU",
  7. "quantizable_data_type": ["input", "weights", "bias", "activation"],
  8. "bit_width": 8,
  9. "method": "diffs",
  10. "round_mode": "std_round",
  11. "symmetry": 启用,
  12. "per_channel": 关闭,
  13. "signed": 启用,
  14. "narrow_range": 关闭,
  15. "scale_type": "power_of_two",
  16. "calib_statistic_method": "modal"

配置完毕后,需要按照上一讲的内容,进行校准和量化:

  1. config_file= "./int8_config.json"
  2. quantizer= torch_quantizer(quant_mode=quant_mode,
  3. module=model,
  4. input_args=(input),
  5. device=device,
  6. quant_config_file=config_file)

唯一的不同,是以上代码部分需要引用新配置的 json 文件。

3.2 执行编译

导入模块

  1. #!pip install -i <https://pypi.tuna.tsinghua.edu.cn/simple> torchsummary
  2. # torchsummary是一个用于查看网络结构,非必须
  3. from torchsummary import summary
  4. import torch, torchvision, random
  5. from pytorch_nndct.apis import Inspector, torch_quantizer
  6. import torchvision.transforms as transforms
  7. from torchvision import models
  8. from tqdm import tqdm
  1. vai_c_xir -x /PATH/TO/quantized.xmodel \\\\
  2. -a /PATH/TO/arch.json \\\\
  3. -o /OUTPUTPATH \\\\
  4. -n netname

编译模型,只需这一条指令。

附:查看支持的型号

  1. !ls -l /opt/vitis_ai/compiler/arch/
  2. ---
  3. total 24
  4. drwxr-xr-x 4 root root 4096 Jun 12 2022 DPUCADF8H
  5. drwxr-xr-x 8 root root 4096 Jun 12 2022 DPUCAHX8H
  6. drwxr-xr-x 5 root root 4096 Jun 12 2022 DPUCAHX8L
  7. drwxr-xr-x 3 root root 4096 Jun 12 2022 DPUCVDX8G
  8. drwxr-xr-x 6 root root 4096 Jun 12 2022 DPUCVDX8H
  9. drwxr-xr-x 5 root root 4096 Jun 12 2022 DPUCZDX8G

附:查看DPUCZDX8G支持的板卡

  1. !ls -l /opt/vitis_ai/compiler/arch/DPUCZDX8G
  2. ---
  3. total 12
  4. drwxr-xr-x 2 root root 4096 Jun 12 2022 KV260
  5. drwxr-xr-x 2 root root 4096 Jun 12 2022 ZCU102
  6. drwxr-xr-x 2 root root 4096 Jun 12 2022 ZCU104

执行完毕编译过程,就可以在对应目录中得到*.xmodel文件了~

4. 总结

本文主要介绍使用Vitis AI工具创建自定义的Xmodol,难点并不在工具本身,而是需要了解很多机器学习的知识。一个很好的出发点是使用Vitis Model Zoo库,是一个包含了大量预训练模型的资源库,这些模型涵盖了多种AI应用领域,如图像分类、目标检测、语义分割、人脸识别、自然语言处理等。我们可以利用这些模型作为一个起点,快速入门并开发自己的应用。这些是由Xilinx官方提供的经过优化和验证的模型,可以直接在Xilinx硬件平台上部署和运行。在熟悉自己的业务的需求,并建立数据集后,我们可以定制的模型。

5. 参考资料

5.1 Featurize 使用技巧

1. 同步盘内容复制。

同步盘,即 work 目录,绝对路径为 /home/featurize/work,是 Featurize 为所有用户提供的一种文件持久化的方案。用户可以将自己的代码、模型文件保存至同步盘中,这样即使在归还实例后同步盘中的文件也不会丢失。

将同步盘文件拷贝至顶层目录,并解压:

  1. !cp ./work/Train_Custom_Dataset-main.zip ./
  2. !unzip Train_Custom_Dataset-main.zip

5.2 迁移学习参考

https://github.com/TommyZihao/Train_Custom_Dataset/tree/mainhttps://github.com/TommyZihao/Train_Custom_Dataset/tree/main/%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BBicon-default.png?t=N7T8https://github.com/TommyZihao/Train_Custom_Dataset/tree/main/%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB

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

闽ICP备14008679号