碎碎念

最近一直在忙毕业设计,头发又少了一点(悲)。期间要用到目标检测这一块,研究了一下PaddleYOLO,发现教程是真不多,很多坑也没人填,官方仓库里的很多说明文件也不存在了,需要自行摸索。边踩边填的过程虽然痛苦,但也算成功跑通了训练 + 部署的完整流程。为了防止下一次又一脸懵逼地重头开始,这里写个记录,也希望能帮到后来人。

顺带一提,PaddleYOLOPP-YOLO,不要搞混了。PaddleYOLO是飞桨官方的目标检测套件,相当于是集成了各种检测模型的训练与部署框架。它目前支持的模型包括YOLOv3YOLOv5PP-YOLOPP-YOLOEYOLO系列最新支持到了YOLOv8,本次训练我们也基于YOLOv8进行展开讲解。

注意:本篇文章可能稍微有些枯燥乏味,因为是以实验报告的内容,可能没有一些华丽的辞藻,更多是关于相关领域的一些术词,可能仅供专业人士研究。

介绍

PaddleYOLO是基于飞桨框架开发的目标检测套件,专注于整合和优化 YOLO 系列模型,旨在提供高性能、轻量级且易于部署的目标检测解决方案。

性能优势

  • 高性能PaddleYOLO采用优化的计算图执行引擎,对模型进行了深度的硬件级优化,能够充分利用GPUCPU资源,实现更快的推理速度。
  • 轻量级:模型结构紧凑,适合资源受限的设备,如嵌入式系统或移动设备,支持实时目标检测。
  • 灵活可扩展:支持多种YOLO架构,包括YOLOv3YOLOv5YOLOv6YOLOv7YOLOv8PP-YOLOPP-YOLOERT-DETR等,用户可根据实际需求调整网络配置,适应不同应用场景。
  • 易于部署:集成了 Paddle Serving,提供完整的模型服务解决方案,便于将模型部署到生产环境,具有良好的跨平台兼容性,支持在多种硬件平台上运行,包括昇腾NPU(比如我们学校那个B鲲鹏平台)。

模型支持列表

模型名称GitHub 仓库地址
YOLOv3ultralytics/yolov3
YOLOv5ultralytics/yolov5
YOLOv6meituan/YOLOv6
YOLOv7WongKinYiu/yolov7
YOLOv8ultralytics/ultralytics
PP-YOLOPaddlePaddle/PaddleDetection
PP-YOLOv2PaddlePaddle/PaddleDetection
PP-YOLOEPaddlePaddle/PaddleDetection
PP-YOLOE+PaddlePaddle/PaddleDetection
RT-DETRlyuwenyu/RT-DETR
YOLOXMegvii-BaseDetection/YOLOX
YOLOv5uultralytics/yolov5
YOLOv7uWongKinYiu/yolov7
YOLOv6Litemeituan/YOLOv6
RTMDetopen-mmlab/mmdetection

MMYOLO对比

MMYOLO是基于OpenMMLab开发的目标检测框架,具有模块化设计,允许轻松定制和扩展,适合研究和开发新技术,相比之下,PaddleYOLO专注于飞桨生态系统,针对飞桨框架进行了优化,提供了高性能和轻量级的目标检测解决方案,特别适合需要与其他飞桨项目(如 PPOCR)集成的应用场景。在本项目的第二阶段,需要使用PPOCR进行文字检测与识别。为了保持框架的一致性,减少跨框架通信和转换的复杂性,在这里我选择了与PPOCR同属飞桨生态的PaddleYOLO作为目标检测模块。

下面我将详细了解一下如何使用PaddleYOLO进行训练内容。

环境配置

首先克隆PaddleYOLO仓库:

1
2
git clone https://github.com/PaddlePaddle/PaddleYOLO.git
cd PaddleYOLO

Python

首先创建一个Python环境,经过我测试,强烈建议3.10环境,可以最大的兼容,如果你使用的conda,使用以下命令:

1
2
conda create -n myenv python=3.10
conda activate myenv

创建环境后,安装一些依赖包:

1
pip install -r requirements.txt  # install

下面需要安装PaddlePaddle

PaddlePaddle

首先点击下方链接打开官网:

向下滑到快速安装部分,如果cuda没有合适的版本可以向上选择,执行命令的过程中可能会有很多报错,不要慌张,这都是因为依赖包的问题,按照要求安装对应包即可。

数据预处理

数据格式

PaddleYOLO中,数据集是支持了三种格式的,分别为VOCCOCOYOLO专用数据集,三者的格式分别如下:

  1. VOC格式:

    PASCAL VOC数据集的目录结构通常如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    VOCdevkit/
    ├── VOC2007/
    │ ├── Annotations/ # 存放 XML 格式的标注文件
    │ ├── JPEGImages/ # 存放图像文件
    │ ├── ImageSets/
    │ │ └── Main/
    │ │ ├── train.txt # 训练集文件名列表
    │ │ ├── val.txt # 验证集文件名列表
    │ │ └── test.txt # 测试集文件名列表

    Annotations/目录下,每个 XML 文件对应一张图像,包含该图像中目标的边界框、类别等信息。

    VOC格式是一个较为传统的数据结构,使用XML文件描述每张图片的标注信息,结构直观、易于阅读。著名标注工具LabelMe的结果就是VOC格式,在早期的目标检测任务中被程序员广泛使用,适合初学者入门和教学场景,但由于不够灵活,难以支持像分割或关键点检测这样的高级任务,现在的使用率已大幅下降。

  2. COCO格式:

    COCO数据集的目录结构示例如下:

    1
    2
    3
    4
    5
    6
    7
    coco/
    ├── annotations/
    │ ├── instances_train2017.json # 训练集标注文件
    │ ├── instances_val2017.json # 验证集标注文件
    ├── images/
    │ ├── train2017/ # 训练集图像
    │ └── val2017/ # 验证集图像

    annotations/ 目录下,标注文件为 JSON 格式,包含图像信息、类别信息、目标的边界框等。

    在目标检测任务中,我们最常用且通用性最强的数据格式是COCO 格式。相比于VOCYOLO格式,COCO拥有更丰富的结构设计和信息表达能力,它不仅支持物体检测,还可以扩展到实例分割、关键点检测、多标签分类等任务,因此被广泛应用于商业级项目和科研场景。几乎所有主流的检测框架,包括MMDetectionYOLOv5/v8PaddleYOLO等,都原生支持COCO格式的数据,使其在模型训练、测试和部署中都非常方便。

  3. YOLO格式:

    YOLO格式的数据集目录结构通常如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    yolo_dataset/
    ├── images/
    │ ├── train/ # 训练集图像
    │ ├── val/ # 验证集图像
    │ └── test/ # 测试集图像(可选)
    ├── labels/
    │ ├── train/ # 训练集标注文件
    │ ├── val/ # 验证集标注文件
    │ └── test/ # 测试集标注文件(可选)

    labels/ 目录下,每个标注文件对应一张图像,采用纯文本格式,每行表示一个目标,包含类别索引、边界框中心坐标、宽度和高度,所有值均为归一化后的相对值。

    YOLO专用格式则以极简著称,每张图像对应一个 .txt 文件,每行标注一个目标,格式紧凑、易于解析,适合在资源受限或对实时性要求高的边缘设备中使用。不过,其表达能力有限,仅支持类别与边框信息,不适用于需要更复杂标注的任务,并且在一些检测框架中仍需手动转换为COCO格式才能使用。

因此,综合考虑框架兼容性、后续扩展性以及整体便携性,我个人更加推荐在PaddleYOLO中使用COCO格式的数据集。

数据准备

本次毕设我选择了船舶方向的研究,所以这里我采用了两个知名航海船舶数据集:SeashipsMCShips,链接如下:

这里我就以第一个为例,如果需要融合数据,只需要修改代码的类别数量即可。

格式转换

以上二者数据都是VOC格式的,这里我在网上找到了以下代码进行转换:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import os
import cv2
import json
import shutil
import xml.etree.ElementTree as ET
from tqdm import tqdm

# Seaships 数据集的类别
SEASHIPS_CLASSES = (
'ore carrier', 'bulk cargo carrier', 'general cargo ship', 'container ship', 'fishing boat', 'passenger ship'
# 'warship', 'civilianship'
)

# 将类别名称映射为 COCO 格式的 category_id
label_ids = {name: i + 1 for i, name in enumerate(SEASHIPS_CLASSES)}

def parse_xml(xml_path):
"""
解析 XML 文件,提取标注信息。
"""
tree = ET.parse(xml_path)
root = tree.getroot()

objects = []
for obj in root.findall('object'):
# 解析类别名称
name = obj.find('name').text
if name not in label_ids:
print(f"警告: 未知类别 '{name}',跳过该对象。")
continue

# 解析 difficult 标签
difficult_tag = obj.find('difficult')
difficult = int(difficult_tag.text) if difficult_tag is not None else 0

# 解析边界框
bnd_box = obj.find('bndbox')
if bnd_box is not None:
bbox = [
int(bnd_box.find('xmin').text),
int(bnd_box.find('ymin').text),
int(bnd_box.find('xmax').text),
int(bnd_box.find('ymax').text)
]
else:
print(f"警告: 在文件 {xml_path} 中未找到 <bndbox> 标签,跳过该对象。")
continue

# 添加到对象列表
objects.append({
'name': name,
'label_id': label_ids[name],
'difficult': difficult,
'bbox': bbox
})

return objects

def load_split_files(split_dir):
"""
加载划分文件(train.txt, val.txt, test.txt)。
"""
split_files = {}
for split_name in ['train', 'val', 'test']:
split_path = os.path.join(split_dir, f'{split_name}.txt')
if os.path.exists(split_path):
with open(split_path, 'r') as f:
split_files[split_name] = [line.strip() for line in f.readlines()]
else:
print(f"警告: 未找到 {split_name}.txt 文件,跳过该划分。")
split_files[split_name] = []
return split_files

def convert_to_coco(image_dir, xml_dir, split_dir, output_dir):
"""
将 Seaships 数据集转换为 COCO 格式,并根据划分文件划分数据集。
"""
# 创建输出目录
os.makedirs(os.path.join(output_dir, 'annotations'), exist_ok=True)
os.makedirs(os.path.join(output_dir, 'train'), exist_ok=True)
os.makedirs(os.path.join(output_dir, 'val'), exist_ok=True)
os.makedirs(os.path.join(output_dir, 'test'), exist_ok=True)

# 加载划分文件
split_files = load_split_files(split_dir)

# 定义 COCO 格式的基本结构
def create_coco_structure():
return {
"info": {
"description": "Seaships Dataset",
"version": "1.0",
"year": 2023,
"contributor": "Your Name",
"date_created": "2023-10-01"
},
"licenses": [],
"images": [],
"annotations": [],
"categories": [
{"id": i + 1, "name": name, "supercategory": "none"}
for i, name in enumerate(SEASHIPS_CLASSES)
]
}

# 处理每个数据集
for split_name, file_names in split_files.items():
coco_data = create_coco_structure()
annotation_id = 1

for file_name in tqdm(file_names, desc=f"处理 {split_name} 数据集"):
xml_file = os.path.join(xml_dir, f'{file_name}.xml')
image_name = f'{file_name}.jpg'
image_path = os.path.join(image_dir, image_name)

# 检查图像文件和 XML 文件是否存在
if not os.path.exists(image_path):
print(f"警告: 图像文件 {image_name} 不存在,跳过该标注文件。")
continue
if not os.path.exists(xml_file):
print(f"警告: 标注文件 {xml_file} 不存在,跳过该图像文件。")
continue

# 读取图像尺寸
image = cv2.imread(image_path)
height, width, _ = image.shape

# 添加图像信息
image_id = len(coco_data['images']) + 1
coco_data['images'].append({
"id": image_id,
"file_name": image_name,
"width": width,
"height": height
})

# 解析 XML 文件
objects = parse_xml(xml_file)
for obj in objects:
xmin, ymin, xmax, ymax = obj['bbox']
bbox = [xmin, ymin, xmax - xmin, ymax - ymin] # COCO 格式的 bbox 是 [x, y, width, height]
area = (xmax - xmin) * (ymax - ymin)

coco_data['annotations'].append({
"id": annotation_id,
"image_id": image_id,
"category_id": obj['label_id'],
"bbox": bbox,
"area": area,
"iscrowd": 0,
"difficult": obj['difficult']
})
annotation_id += 1

# 复制图像文件到对应的文件夹
shutil.copy(image_path, os.path.join(output_dir, split_name, image_name))

# 保存 COCO 格式的标注文件
with open(os.path.join(output_dir, 'annotations', f'instances_{split_name}.json'), 'w') as f:
json.dump(coco_data, f, indent=4)

print(f"转换完成,结果已保存到 {output_dir}")

# 设置路径
image_dir = ".\dataset\Mcship_lite\JPEGImages" # 图像文件目录
xml_dir = ".\dataset\Mcship_lite\Annotations" # XML 标注文件目录
split_dir = ".\dataset\Mcship_lite\ImageSets\Main" # 划分文件目录(包含 train.txt, val.txt, test.txt)
output_dir = ".\dataset\Mcship_lite-coco" # 输出的 COCO 格式文件夹

# 执行转换
convert_to_coco(image_dir, xml_dir, split_dir, output_dir)

只需要修改下面的路径即可,最终会直接输出标准格式的COCO数据集,这样我们的数据预处理部分也就实现了。

调整配置

下面我们需要修改一些配置,通过配置,正确的指向我们所需要的模型,数据。

数据库配置

首先配置数据库,为了方便,我们将数据库放置在了PaddleYOLO/dataset文件夹内,然后开始配置,如果文件克隆完整,我们可以在PaddleYOLO/configs/datasets目录下看到一些数据集配置:

1
2
3
4
5
6
7
8
9
10
PaddleYOLO/
├── configs/
│ ├── datasets/
│ │ ├── Coco_Detection.yml # 配置 COCO 数据集,用于物体检测任务
│ │ ├── Coco_instance.yml # 配置 COCO 数据集的实例分割任务
│ │ ├── object365_Detection.yml # 配置 Object365 数据集,用于多类物体检测任务
│ │ ├── OpenImagesv7_Detection.yml # 配置 Open Images v7 数据集,用于大规模目标检测任务
│ │ ├── roadsign_voc.yml # 配置 RoadSign 数据集,用于交通标志检测任务,兼容 VOC 格式
│ │ ├── Visdrone_Detection.yml # 配置 VisDrone 数据集,用于无人机图像物体检测与追踪
│ │ └── Voc.yml # 配置 PASCAL VOC 数据集,用于传统物体检测任务

按照我们的要求,我们进行的是船舶识别检测,所以选择第一个配置文件作为基础文件,复制该文件,比如这里我是创建了一个Coco_Detection_Mydataset.yml文件,存储我个人的数据集配置,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
metric: COCO
num_classes: 6

TrainDataset:
name: COCODataSet
image_dir: train
anno_path: annotations/instances_train.json
dataset_dir: dataset/SeaShips-coco
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']

EvalDataset:
name: COCODataSet
image_dir: val
anno_path: annotations/instances_val.json # annotations/instances_val.json
dataset_dir: dataset/SeaShips-coco

TestDataset:
name: ImageFolder
image_dir: test # test
anno_path: annotations/instances_test.json # annotations/instances_val.json # also support txt (like VOC's label_list.txt)
dataset_dir: dataset/SeaShips-coco # if set, anno_path will be 'dataset_dir/anno_path'

需要修改的内容是第二行的类别,和每个里面的路径和地址,这里用的相对地址,注意个人存放路径,其他不要修改。

训练配置

这里我用的是YOLOv8,并且选择了M*版本模型,是一个兼顾速度和效果的版本,找到目录PaddleYOLO\configs\yolov8,目录如下:

1
2
3
4
5
6
7
8
9
10
11
12
PaddleYOLO/
├── configs/
│ ├── yolov8/
│ │ ├── _base_
│ │ ├── openimagev7 # 配置 OpenImages v7 数据集的 YOLOv8 训练
│ │ ├── README.md # 该文件包含 YOLOv8 配置的说明和使用方法
│ │ ├── yolov8_l_500e_coco.yml # 配置 YOLOv8 使用 COCO 数据集,训练 500 epochs,模型为 L 版本
│ │ ├── yolov8_m_500e_coco.yml # 配置 YOLOv8 使用 COCO 数据集,训练 500 epochs,模型为 M 版本
│ │ ├── yolov8_n_500e_coco.yml # 配置 YOLOv8 使用 COCO 数据集,训练 500 epochs,模型为 N 版本
│ │ ├── yolov8_s_500e_coco.yml # 配置 YOLOv8 使用 COCO 数据集,训练 500 epochs,模型为 S 版本
│ │ ├── yolov8_x_500e_coco.yml # 配置 YOLOv8 使用 COCO 数据集,训练 500 epochs,模型为 X 版本
│ │ └── yolov8p6_x_500e_coco.yml # 配置 YOLOv8p6 使用 COCO 数据集,训练 500 epochs,模型为 X 版本

以上不同的配置文件表示不同的模型版本,以下是这些配置文件的简要说明:

配置文件模型版本训练数据集训练周期说明
yolov8_l_500e_coco.ymlL 版本COCO500 epochsYOLOv8 L 版本,适合高精度任务,计算资源需求较高。
yolov8_m_500e_coco.ymlM 版本COCO500 epochsYOLOv8 M 版本,精度与速度平衡,适中任务。
yolov8_n_500e_coco.ymlN 版本COCO500 epochsYOLOv8 N 版本,适合资源有限的环境,速度较快。
yolov8_s_500e_coco.ymlS 版本COCO500 epochsYOLOv8 S 版本,适合较小任务,计算资源要求低。
yolov8_x_500e_coco.ymlX 版本COCO500 epochsYOLOv8 X 版本,精度较高,适用于复杂任务。
yolov8p6_x_500e_coco.ymlX 版本(P6)COCO500 epochsYOLOv8p6 X 版本,优化精度和性能,适合高精度应用。

这些版本的区别主要在于模型大小、精度与计算资源需求的平衡,按照自己的需求选择即可,选哪个都可以运行,训练周期我们是可以控制的。

这里我需要配置m版本模型,为了防止破坏项目结构,新建一个文件放置我自己的配置文件,比如yolov8_m_500e_coco_mydataset.yml,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
_BASE_: [
'../datasets/coco_detection_mydataset.yml',
'../runtime.yml',
'_base_/optimizer_500e_high_mydataset.yml',
'_base_/yolov8_cspdarknet.yml',
'_base_/yolov8_reader_high_aug.yml',
]
depth_mult: 0.67
width_mult: 0.75

log_iter: 50
snapshot_epoch: 5
weights: output/yolov8_m_500e_coco/model_final


YOLOv8CSPDarkNet:
last_stage_ch: 768 # The actual channel is int(768 * width_mult), not int(1024 * width_mult) as in YOLOv5


TrainReader:
batch_size: 8 # default 8 gpus, total bs = 128

在第一个_BASE_部分指定该配置文件引用了一些其他的配置,比如第一个是数据集配置文件,第二个为配置和管理模型训练或推理时的运行时环境参数配置文件,第三个为优化器配置文件,第四个为使用CSPDarkNet网络架构配置文件,第五个为数据加载起配置文件,这里我们只需要修改第一个和第三个,其余的如果熟练的话,可以按照自己的要求进行定制,第一个指向前面我们修改的数据集配置文件,第三个指定了一些学习率和学习率增量等一些配置。

我们先看上面的训练配置文件,其中配置作用如下:

  • depth_mult:
    控制网络深度的缩放比例。0.67 表示将网络的层数减少到原来的 67%,从而减少模型的复杂度和计算量,但可能会影响模型的精度。
  • width_mult:
    控制网络宽度的缩放比例。0.75 表示将网络每层的通道数减少到原来的 75%,从而减少模型的参数量和计算复杂度,但可能也会影响性能。
  • log_iter:
    设置日志输出的频率。50 表示每经过50次训练迭代就记录一次日志信息。这有助于监控训练进度、损失变化和其他重要指标。
  • snapshot_epoch:
    设置模型保存的频率。5 表示每训练5个epoch保存一次模型,以便在训练过程中进行检查点保存,便于恢复或调优。
  • weights:
    指定预训练模型的路径,output/yolov8_m_500e_coco/model_final 指向预训练的权重文件。这些预训练权重有助于加速收敛,特别是在类似任务的微调过程中。
  • YOLOv8CSPDarkNet:
    • last_stage_ch:
      设置YOLOv8 CSPDarkNet模型最后一层的通道数。768 是实际通道数(在应用了 width_mult 后是 int(768 * 0.75) = 576)。这个参数决定了特征提取网络的宽度,影响模型的复杂度和性能。
  • TrainReader:
    • batch_size:
      设置每个 GPU 上的批处理大小。8 表示每个GPU在一次迭代中处理 8 个样本。如果使用多个GPU,总批处理大小会更大,当然如果算力有限,那就越小越好啦!

优化器配置

这里其实没什么好说的,主要能修改的就是学习率和轮次了,这个都需要按照自己的项目需求进行修改,我这里就简单测试一下,后续会上算力机器进行训练,所以简单训练个50轮即可,该文件就是上面_BASE_配置中第三个配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# epoch: 50

LearningRate:
base_lr: 0.005
schedulers:
- !YOLOv5LRDecay
max_epochs: 500
min_lr_ratio: 0.1 #
- !ExpWarmup
epochs: 5 #3

OptimizerBuilder:
optimizer:
type: Momentum
momentum: 0.937
use_nesterov: True
regularizer:
factor: 0.0005
type: L2
clip_grad_by_value: 10.

到了目前,所有的配置基本结束,下面开始训练。

训练和测试

这里其实就是一个命令的事情,所以我按照官网的说法,实现了一个bat文件,按照自己的要求进行注释和打开注释即可运行:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@echo off
setlocal enabledelayedexpansion

:: 设置模型名称和作业名称
set model_name=yolov8
set job_name=yolov8_m_500e_coco_mydataset

set config=configs\%model_name%\%job_name%.yml
set log_dir=log_dir\%job_name%
set weights=output\%job_name%\model_final.pdparams

:: 1. 训练(单卡/多卡),加 --eval 表示边训边评估,加 --amp 表示混合精度训练
set CUDA_VISIBLE_DEVICES=0
python -m paddle.distributed.launch --log_dir=%log_dir% --gpus 0 tools/train.py -c %config% --eval --amp --use_vdl True --vdl_log_dir=vdl_dir/scalar -o pretrain_weights=./models/yolov8_m_500e_coco.pdparams

:: 2. 评估,加 --classwise 表示输出每一类mAP
:: python tools/eval.py -c %config% -o weights=%weights% --classwise

:: 3. 预测(单张图/图片文件夹)
python tools/infer.py -c %config% -o weights=%weights% --infer_img=./dataset/MyDataSet-coco/train/000002.jpg --draw_threshold=0.2
:: python tools/infer.py -c %config% -o weights=%weights% --infer_dir=demo\ --draw_threshold=0.5

:: 4. 导出模型,以下3种模式选一种
:: 普通导出
:: python tools/export_model.py -c %config% -o weights=%weights%

:: exclude_post_process 去除后处理导出,返回和 YOLOv5 导出 ONNX 时相同格式的 concat 后的 1 个 Tensor
:: python tools/export_model.py -c %config% -o weights=%weights% exclude_post_process=True

:: exclude_nms 去除 NMS 导出,返回 2 个 Tensor
:: python tools/export_model.py -c %config% -o weights=%weights% exclude_nms=True

:: 5. 部署预测
:: python deploy/python/infer.py --model_dir=output_inference\%job_name% --image_file=demo\000000014439_640x640.jpg --device=GPU

:: 6. 部署测速,加 “--run_mode=trt_fp16” 表示在 TensorRT FP16 模式下测速
:: python deploy/python/infer.py --model_dir=output_inference\%job_name% --image_file=demo\000000014439_640x640.jpg --device=GPU --run_benchmark=True

:: 7. ONNX 导出
:: paddle2onnx --model_dir output_inference\%job_name% --model_filename model.pdmodel --params_filename model.pdiparams --opset_version 12 --save_file %job_name%.onnx

:: 8. ONNX TRT 测速
:: "C:\Program Files\TensorRT-8.0.3.4\bin\trtexec.exe" --onnx=%job_name%.onnx --workspace=4096 --avgRuns=10 --shapes=input:1x3x640x640 --fp16
:: "C:\Program Files\TensorRT-8.0.3.4\bin\trtexec.exe" --onnx=%job_name%.onnx --workspace=4096 --avgRuns=10 --shapes=input:1x3x640x640 --fp32

echo 完成!
pause

以上脚本包含训练和测试部署等所有命令,我仅测试了训练和测试,如果还有更高的要求请按照官方文档进行配置,最终的结果会在/output显示出来,可能图上的标注会和你的标注无法对应上,这是正产现象,因为PaddleYOLOcoco数据集标注字典内置了,目前我还没找到修改的地方,完全不影响,因为结果是标注ID,如果需要可视化自行实现一个即可。

参考文章

声明

  • 以上内容仅供学术研究和学习交流使用,如有侵权,请联系我进行删除处理。
  • 若有任何问题或需要进一步讨论,请随时联系我的邮箱:01@liushen.fun

每日一图

图片来自哲风壁纸

静谧教室