赞
踩
目录
本文分享完整使用 Vitis AI 开发实践过程,包括进行迁移学习,使用量化工具对浮点模型进行量化,并将 xmodel 部署在 DPU 照中。
使用迁移学习的方法,将预训练的 resnet18 模型从原来的 1000 类分类任务,改造为适应自定义的 30 类分类任务。本迁移学习使用同济自豪兄的分类模型。
ResNet18 是一种基于深度残差网络(ResNet)的卷积神经网络模型,由何凯明等人于2015年提出。ResNet 的核心思想是通过引入残差块(Residual Block),解决了深度网络中的梯度消失和退化问题,使得网络可以更深更有效地学习特征。
ResNet18 是 ResNet 系列中最简单的一个模型,共有18层。
根据不同的任务和数据集,迁移学习有以下几种常见的方法:
1. 微调网络:这种方法是在预训练模型的基础上,修改最后一层或几层,并且对整个网络进行微调训练。这种方法适用于新数据集和原数据集相似度较高,且新数据集规模较大的情况。
2. 特征提取:这种方法是将预训练模型看作一个特征提取器,冻结除了最后一层以外的所有层,只修改和训练最后一层。这种方法适用于新数据集和原数据集相似度较高,但新数据集规模较小的情况。
3. 模型蒸馏:这种方法是将预训练模型看作一个教师模型,用它来指导一个更小的学生模型,使学生模型能够学习到教师模型的知识。这种方法适用于新数据集和原数据集相似度较低,或者需要减少模型大小和计算量的情况。
本文省去手动搭建 Pytorch 环境,直接通过云平台选择现成的环境:
Featurizehttps://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 V1.10 版本。
- import time
- import os
-
- import numpy as np
- from tqdm import tqdm
-
- import torch
- import torchvision
- import torch.nn as nn
- import torch.nn.functional as F
-
- import matplotlib.pyplot as plt
- %matplotlib inline
-
- # 忽略红色提示
- import warnings
- warnings.filterwarnings("ignore")
然后导入预训练模型,并查看网络结构:
- model = models.resnet18(pretrained=True) # 载入预训练模型
- summary(model, (3, 224, 224))
-
- ---以下为执行结果
- ----------------------------------------------------------------
- Layer (type) Output Shape Param #
- ================================================================
- Conv2d-1 [-1, 64, 112, 112] 9,408
- BatchNorm2d-2 [-1, 64, 112, 112] 128
- ReLU-3 [-1, 64, 112, 112] 0
- MaxPool2d-4 [-1, 64, 56, 56] 0
- Conv2d-5 [-1, 64, 56, 56] 36,864
- BatchNorm2d-6 [-1, 64, 56, 56] 128
- ReLU-7 [-1, 64, 56, 56] 0
- Conv2d-8 [-1, 64, 56, 56] 36,864
- BatchNorm2d-9 [-1, 64, 56, 56] 128
- ReLU-10 [-1, 64, 56, 56] 0
- BasicBlock-11 [-1, 64, 56, 56] 0
- Conv2d-12 [-1, 64, 56, 56] 36,864
- BatchNorm2d-13 [-1, 64, 56, 56] 128
- ReLU-14 [-1, 64, 56, 56] 0
- Conv2d-15 [-1, 64, 56, 56] 36,864
- BatchNorm2d-16 [-1, 64, 56, 56] 128
- ReLU-17 [-1, 64, 56, 56] 0
- BasicBlock-18 [-1, 64, 56, 56] 0
- Conv2d-19 [-1, 128, 28, 28] 73,728
- BatchNorm2d-20 [-1, 128, 28, 28] 256
- ReLU-21 [-1, 128, 28, 28] 0
- Conv2d-22 [-1, 128, 28, 28] 147,456
- BatchNorm2d-23 [-1, 128, 28, 28] 256
- Conv2d-24 [-1, 128, 28, 28] 8,192
- BatchNorm2d-25 [-1, 128, 28, 28] 256
- ReLU-26 [-1, 128, 28, 28] 0
- BasicBlock-27 [-1, 128, 28, 28] 0
- Conv2d-28 [-1, 128, 28, 28] 147,456
- BatchNorm2d-29 [-1, 128, 28, 28] 256
- ReLU-30 [-1, 128, 28, 28] 0
- Conv2d-31 [-1, 128, 28, 28] 147,456
- BatchNorm2d-32 [-1, 128, 28, 28] 256
- ReLU-33 [-1, 128, 28, 28] 0
- BasicBlock-34 [-1, 128, 28, 28] 0
- Conv2d-35 [-1, 256, 14, 14] 294,912
- BatchNorm2d-36 [-1, 256, 14, 14] 512
- ReLU-37 [-1, 256, 14, 14] 0
- Conv2d-38 [-1, 256, 14, 14] 589,824
- BatchNorm2d-39 [-1, 256, 14, 14] 512
- Conv2d-40 [-1, 256, 14, 14] 32,768
- BatchNorm2d-41 [-1, 256, 14, 14] 512
- ReLU-42 [-1, 256, 14, 14] 0
- BasicBlock-43 [-1, 256, 14, 14] 0
- Conv2d-44 [-1, 256, 14, 14] 589,824
- BatchNorm2d-45 [-1, 256, 14, 14] 512
- ReLU-46 [-1, 256, 14, 14] 0
- Conv2d-47 [-1, 256, 14, 14] 589,824
- BatchNorm2d-48 [-1, 256, 14, 14] 512
- ReLU-49 [-1, 256, 14, 14] 0
- BasicBlock-50 [-1, 256, 14, 14] 0
- Conv2d-51 [-1, 512, 7, 7] 1,179,648
- BatchNorm2d-52 [-1, 512, 7, 7] 1,024
- ReLU-53 [-1, 512, 7, 7] 0
- Conv2d-54 [-1, 512, 7, 7] 2,359,296
- BatchNorm2d-55 [-1, 512, 7, 7] 1,024
- Conv2d-56 [-1, 512, 7, 7] 131,072
- BatchNorm2d-57 [-1, 512, 7, 7] 1,024
- ReLU-58 [-1, 512, 7, 7] 0
- BasicBlock-59 [-1, 512, 7, 7] 0
- Conv2d-60 [-1, 512, 7, 7] 2,359,296
- BatchNorm2d-61 [-1, 512, 7, 7] 1,024
- ReLU-62 [-1, 512, 7, 7] 0
- Conv2d-63 [-1, 512, 7, 7] 2,359,296
- BatchNorm2d-64 [-1, 512, 7, 7] 1,024
- ReLU-65 [-1, 512, 7, 7] 0
- BasicBlock-66 [-1, 512, 7, 7] 0
- AdaptiveAvgPool2d-67 [-1, 512, 1, 1] 0
- Linear-68 [-1, 1000] 513,000
- ================================================================
- Total params: 11,689,512
- Trainable params: 11,689,512
- Non-trainable params: 0
- ----------------------------------------------------------------
- Input size (MB): 0.57
- Forward/backward pass size (MB): 62.79
- Params size (MB): 44.59
- Estimated Total Size (MB): 107.96
- ----------------------------------------------------------------
可以原始看到最后一层有1000个特征输出,对应1000分类。我们要做的,就是使用特征提取方法,修改最后一层(FC),实现一个30分类的特征输出。
查看当前 fc 层状态:
- print(model.fc)
- ---
- 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 层状态:
- print(model.fc)
- ---
- Linear(in_features=512, out_features=30, bias=True)
只微调训练最后一层全连接层的参数,其它层冻结
optimizer = optim.Adam(model.fc.parameters())
optimizer = optim.Adam(model.parameters())
配置优化器,只微调输出层(FC),然后执行训练:
- # 遍历每个 EPOCH
- for epoch in tqdm(range(EPOCHS)):
- model.train()
- for images, labels in train_loader: # 获取训练集的一个 batch,包含数据和标注
- images = images.to(device)
- labels = labels.to(device)
-
- outputs = model(images) # 前向预测,获得当前 batch 的预测结果
- loss = criterion(outputs, labels) # 比较预测结果和标注,计算当前 batch 的交叉熵损失函数
-
- optimizer.zero_grad()
- loss.backward() # 损失函数对神经网络权重反向传播求梯度
- optimizer.step() # 优化更新神经网络权重
-
- ---以下为执行结果
- 100%|██████████| 20/20 [03:04<00:00, 9.24s/it]
在测试集的准确度为:85.900 %
注:本文不详解如何构建数据集加载器,以及测试部分相关代码,只保留关键代码以演示使用迁移学习过程,需要读者自行补齐机器学习相关知识。
导出迁移学习后的结果模型:
torch.save(model, 'resnet18_out30.pth')
将在当前工作目录下,生成 resnet18_out30.pth 文件。
默认的量化配置如下:
- "convert_relu6_to_relu": 关闭,
- "include_cle": 启用,
- "keep_first_last_layer_accuracy": 关闭,
- "keep_add_layer_accuracy": 关闭,
- "include_bias_corr": 开,
- "target_device": "DPU",
- "quantizable_data_type": ["input", "weights", "bias", "activation"],
- "bit_width": 8,
- "method": "diffs",
- "round_mode": "std_round",
- "symmetry": 启用,
- "per_channel": 关闭,
- "signed": 启用,
- "narrow_range": 关闭,
- "scale_type": "power_of_two",
- "calib_statistic_method": "modal"
配置完毕后,需要按照上一讲的内容,进行校准和量化:
- config_file= "./int8_config.json"
- quantizer= torch_quantizer(quant_mode=quant_mode,
- module=model,
- input_args=(input),
- device=device,
- quant_config_file=config_file)
唯一的不同,是以上代码部分需要引用新配置的 json 文件。
导入模块
- #!pip install -i <https://pypi.tuna.tsinghua.edu.cn/simple> torchsummary
- # torchsummary是一个用于查看网络结构,非必须
-
- from torchsummary import summary
- import torch, torchvision, random
- from pytorch_nndct.apis import Inspector, torch_quantizer
- import torchvision.transforms as transforms
- from torchvision import models
- from tqdm import tqdm
- vai_c_xir -x /PATH/TO/quantized.xmodel \\\\
- -a /PATH/TO/arch.json \\\\
- -o /OUTPUTPATH \\\\
- -n netname
编译模型,只需这一条指令。
附:查看支持的型号
- !ls -l /opt/vitis_ai/compiler/arch/
-
- ---
- total 24
- drwxr-xr-x 4 root root 4096 Jun 12 2022 DPUCADF8H
- drwxr-xr-x 8 root root 4096 Jun 12 2022 DPUCAHX8H
- drwxr-xr-x 5 root root 4096 Jun 12 2022 DPUCAHX8L
- drwxr-xr-x 3 root root 4096 Jun 12 2022 DPUCVDX8G
- drwxr-xr-x 6 root root 4096 Jun 12 2022 DPUCVDX8H
- drwxr-xr-x 5 root root 4096 Jun 12 2022 DPUCZDX8G
附:查看DPUCZDX8G支持的板卡
- !ls -l /opt/vitis_ai/compiler/arch/DPUCZDX8G
-
- ---
- total 12
- drwxr-xr-x 2 root root 4096 Jun 12 2022 KV260
- drwxr-xr-x 2 root root 4096 Jun 12 2022 ZCU102
- drwxr-xr-x 2 root root 4096 Jun 12 2022 ZCU104
执行完毕编译过程,就可以在对应目录中得到*.xmodel文件了~
本文主要介绍使用Vitis AI工具创建自定义的Xmodol,难点并不在工具本身,而是需要了解很多机器学习的知识。一个很好的出发点是使用Vitis Model Zoo库,是一个包含了大量预训练模型的资源库,这些模型涵盖了多种AI应用领域,如图像分类、目标检测、语义分割、人脸识别、自然语言处理等。我们可以利用这些模型作为一个起点,快速入门并开发自己的应用。这些是由Xilinx官方提供的经过优化和验证的模型,可以直接在Xilinx硬件平台上部署和运行。在熟悉自己的业务的需求,并建立数据集后,我们可以定制的模型。
1. 同步盘内容复制。
同步盘,即 work 目录,绝对路径为 /home/featurize/work
,是 Featurize 为所有用户提供的一种文件持久化的方案。用户可以将自己的代码、模型文件保存至同步盘中,这样即使在归还实例后同步盘中的文件也不会丢失。
将同步盘文件拷贝至顶层目录,并解压:
- !cp ./work/Train_Custom_Dataset-main.zip ./
- !unzip Train_Custom_Dataset-main.zip
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%BBhttps://github.com/TommyZihao/Train_Custom_Dataset/tree/main/%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。