6. RT-DETR(目标检测)¶
RT-DETR是百度团队提出基于Transformer的实时的端到端检测器。
RT-DETR设计了一个高效的混合编码器,通过解耦尺度内交互和跨尺度融合来高效处理多尺度特征, 并提出了IoU感知的查询选择机制,以优化解码器查询的初始化。
此外,RT-DETR支持通过使用不同的解码器层来灵活调整推理速度,而不需要重新训练,有助于实时目标检测器的实际应用。
RT-DETRv2在SOTA的RT-DETR的基础上,引入了灵活的解码器,并运用了一系列有效的训练策略, 为适应各种部署方案,解码器现在提供了一个利用离散采样而非网格采样的选项。
RT-DETR更多详情请查看论文:
DETRs Beat YOLOs on Real-time Object Detection
RT-DETRv2: Improved Baseline with Bag-of-Freebies for Real-Time Detection Transformer
RT-DETR/RT-DETRv2源码地址:https://github.com/lyuwenyu/RT-DETR 。
本章将简单测试RT-DETRv2模型,并在鲁班猫板卡上部署测试。
6.1. RT-DETRv2推理测试¶
RT-DETRv2源码在 RT-DETR 工程文件中,教程测试使用Pytorch,就是对应工程rtdetrv2_pytorch目录下的源码。 使用paddlepaddle的参考下 这里
使用Anaconda进行环境管理,创建一个环境:
conda create -n rtdetr python=3.10
conda activate rtdetr
# 配置pip源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/
# 拉取
git clone https://github.com/lyuwenyu/RT-DETR
# 切换到rtdetrv2_pytorch目录下
cd RT-DETR/rtdetrv2_pytorch
pip install -r requirements.txt
测试rtdetrv2_pytorch源码中提供的推理例程,查看rtdetrv2_pytorch目录下README.md文件,获取配置和权重文件。 为了与后面板卡上部署,教程测试的是离散采样调优模型RT-DETRv2-S_dsp,基础模型采样方法是grid_sampling。
cd RT-DETR/rtdetrv2_pytorch
# 获取RT-DETRv2-S_dsp模型的checkpoint,使用的配置文件configs/rtdetrv2/rtdetrv2_r18vd_dsp_3x_coco.yml
wget https://github.com/lyuwenyu/storage/releases/download/v0.1/rtdetrv2_r18vd_dsp_3x_coco.pth
cp references/deploy/rtdetrv2_torch.py ./
# -c指定配置文件,-r指定checkpoint路径,--im-file指定测试文件路径
python rtdetrv2_torch.py -c configs/rtdetrv2/rtdetrv2_r18vd_dsp_3x_coco.yml \
-r ./rtdetrv2_r18vd_dsp_3x_coco.pth --im-file=./test.jpg
结果保存在但其目录下results_0.jpg(这里指定了一个测试文件),教程测试结果如下:
6.2. 模型转换¶
将RT-DETRv2-S_dsp模型导出成onnx模型,简单修改源码rtdetrv2_pytorch/tools/export_onnx.py, 使导出的onnx模型不包括源码提供的后处理,输入固定为(1, 3, 640, 640),模型输出pred_logits添加sigmoid。具体修改如下:
6.2.1. 导出onnx模型¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # 省略............
class Model(nn.Module):
def __init__(self, ) -> None:
super().__init__()
self.model = cfg.model.deploy()
self.postprocessor = cfg.postprocessor.deploy()
def forward(self, images):
outputs = self.model(images)
# outputs = self.postprocessor(outputs, orig_target_sizes) orig_target_sizes
outputs = torch.sigmoid(outputs['pred_logits']), outputs['pred_boxes']
return outputs
model = Model()
data = torch.rand(1, 3, 640, 640)
model.eval()
torch.onnx.export(
model,
data,
args.output_file,
input_names=['images'],
output_names=['output1', 'output2'],
opset_version=16,
verbose=False,
do_constant_folding=True,
)
|
导出onnx模型:
# 获取rtdetrv2_r18vd_dsp_3x_coco.pth 权重文件,如果前面获取了就不用
wget https://github.com/lyuwenyu/storage/releases/download/v0.1/rtdetrv2_r18vd_dsp_3x_coco.pth
# 使用下面命令导出rtdetrv2_r18vd_dsp.onnx模型
# -c指定配置文件,-r指定checkpoint路径,--im-file指定测试文件路径,-o指定输出模型
(rtdetr) llh@llh:/xxx$ python tools/export_onnx_dsp.py -c configs/rtdetrv2/rtdetrv2_r18vd_dsp_3x_coco.yml -r \
./rtdetrv2_r18vd_dsp_3x_coco.pth --check -o rtdetrv2_r18vd_dsp.onnx
# 省略................
Check export onnx model done...
6.2.2. 转换成rknn模型¶
使用toolkit2工具将onnx模型转换成rknn模型,注意这里使用fp16,不经过INT8量化或者混合量化。 实际测试INT8量化模型部署时存在infinity等原因,不能在板卡上部署。
# 教程测试lubancat4 设置rk3588
# Usage: python3 onnx2rknn.py onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]
(toolkit2.2) llh@llh:/xxx$ python onnx2rknn.py rtdetrv2_r18vd_dsp.onnx rk3588 fp
I rknn-toolkit2 version: 2.2.0
--> Config model
done
--> Loading model
I Loading : 100%|██████████████████████████████████████████████| 247/247 [00:00<00:00, 24820.15it/s]
done
--> Building model
I OpFusing 0: 100%|███████████████████████████████████████████████| 100/100 [00:02<00:00, 48.84it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:04<00:00, 20.49it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:08<00:00, 11.22it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:09<00:00, 10.94it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:09<00:00, 10.22it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:09<00:00, 10.12it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:10<00:00, 9.94it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:10<00:00, 9.54it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:10<00:00, 9.44it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:11<00:00, 8.40it/s]
I rknn building ...
I rknn buiding done.
done
--> Export rknn model
done
6.3. 板卡上部署测试¶
部署测试使用rknpu2 runtime提供的c/c++接口,接口使用教程请参考下前面章节。
直接部署前面转换出的rtdetrv2_r18vd_dsp.rknn模型,会出现段错误 ,可能是模型中的Topk导致,经过测试自定义Topk算子可以避免这个问题 (未来版本的toolkit2可能不会出现这个问题)。
Topk是onnx标准算子,只需要在部署程序中自定义Topk算子,然后注册这个cpu算子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // 省略................
/**
* compute_custom_topk_fp
* */
int compute_custom_topk_fp(rknn_custom_op_context* op_ctx, rknn_custom_op_tensor* inputs, uint32_t n_inputs,
rknn_custom_op_tensor* outputs, uint32_t n_outputs)
{
unsigned char* in_ptr = (unsigned char*)inputs[0].mem.virt_addr + inputs[0].mem.offset;
unsigned char* out_ptr1 = (unsigned char*)outputs[1].mem.virt_addr + outputs[1].mem.offset;
const float* in_data = (const float*)in_ptr;
float * out_data1 = (float*)out_ptr1;
int N = inputs[0].attr.dims[1];
int K = outputs[1].attr.dims[1];
topk(in_data, out_data1, N, K);
return 0;
}
// 省略................
// register a custom op
rknn_custom_op user_op[1];
memset(user_op, 0, sizeof(rknn_custom_op));
strncpy(user_op[0].op_type, "TopK", RKNN_MAX_NAME_LEN - 1);
user_op[0].version = 1;
user_op[0].target = RKNN_TARGET_TYPE_CPU;
user_op[0].compute = compute_custom_topk_fp;
ret = rknn_register_custom_ops(ctx, user_op, 1);
if (ret < 0) {
printf("rknn_register_custom_op fail! ret = %d\n", ret);
return -1;
}
// 省略................
|
编译测试例程:
# 板卡上获取配套例程(例程可能没有及时更新)
git clone https://gitee.com/LubanCat/lubancat_ai_manual_code.git
# 切换到rt-detr
cd lubancat_ai_manual_code/examples/rt-detr/cpp
# 编译例程
cat@lubancat:~/xxx/examples/rt-detr/cpp$ ./build-linux.sh -t rk3588
./build-linux.sh -t rk3588
===================================
TARGET_SOC=rk3588
INSTALL_DIR=/xxx/examples/rt-detr/cpp/install/rk3588_linux
BUILD_DIR=/xxx/examples/rt-detr/cpp/build/build_rk3588_linux
ENABLE_DMA32=TRUE
DISABLE_RGA=OFF
BUILD_TYPE=Release
ENABLE_ASAN=OFF
CC=aarch64-linux-gnu-gcc
CXX=aarch64-linux-gnu-g++
===================================
# 省略................
Scanning dependencies of target rtdetr_image_demo
[ 75%] Building CXX object CMakeFiles/rtdetr_image_demo.dir/postprocess.cc.o
[ 83%] Building CXX object CMakeFiles/rtdetr_image_demo.dir/rknpu2/rtdetr.cc.o
[ 91%] Building CXX object CMakeFiles/rtdetr_image_demo.dir/rtdetr_image_demo.cc.o
[100%] Linking CXX executable rtdetr_image_demo
[100%] Built target rtdetr_image_demo
[ 16%] Built target fileutils
[ 33%] Built target imageutils
[ 50%] Built target imagedrawing
[ 83%] Built target rtdetr_image_demo
[100%] Built target audioutils
Install the project...
# 省略................
运行例程:
# 设置cpu、npu频率最高,然后运行例程
cat@lubancat:~/xxx/examples/rt-detr/cpp$
load lable ./model/coco_80_labels_list.txt
model input num: 1, output num: 2
input tensors:
index=0, name=images, n_dims=4, dims=[1, 640, 640, 3], n_elems=1228800, size=2457600,
w_stride = 640, size_with_stride = 2457600, fmt=NHWC, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=output1, n_dims=3, dims=[1, 300, 80], n_elems=24000, size=48000,
w_stride = 0, size_with_stride = 48000, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
index=1, name=output2, n_dims=3, dims=[1, 300, 4], n_elems=1200, size=2400,
w_stride = 0, size_with_stride = 2400, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is NHWC input fmt
model input height=640, width=640, channel=3
origin size=640x640 crop size=640x640
input image: 640 x 640, subsampling: 4:2:0, colorspace: YCbCr, orientation: 1
-- read_image use: 4.527000 ms
scale=1.000000 dst_box=(0 0 639 639) allow_slight_change=1 _left_offset=0 _top_offset=0 padding_w=0 padding_h=0
rga_api version 1.10.1_[0]
rknn_run
-- inference_rtdetr_model use: 331.776001 ms
bus @ (85 133 557 437) 0.949
person @ (108 239 224 535) 0.946
person @ (212 240 284 510) 0.929
person @ (476 235 560 524) 0.954
person @ (80 327 124 517) 0.883
write_image path: out.png width=640 height=640 channel=3 data=0x557dcedee0
测试结果保存当前目录下out.png,教程测试结果截图如下:
以上就是在lubancat上简单部署RT-DETRv2,详情请查看配套例程,可以自行去优化。