posts - 23,  comments - 14,  views - 34234

主要目的是在没有GPU的情况下,上手ppyolo的训练过程,看看paddlepaddle是不是顺手。纯代码实验。PaddleDetection在下文中简称ppdet。

 

1 基本环境

1.1 软件组成和版本
Windows>= 7

python=3.8

paddle.__version__ '2.3.2'
ppdet.__version__ '2.4.0'

1.2 数据集
HelmetDetection(VOC)

1.3 网络结构
ppyolo_r50vd_dcn

1.4 预训练模型
ResNet50_vd_ssld_pretrained.pdparams

 

2 环境的搭建

2.1 PaddlePaddle的安装

PaddleDetection依赖apddlepaddle,对于paddlepaddle来说,CPU分为支持avx和不支持avx(比如:Intel Core 2 Q8300),需要手动执行安装。

 

不支持avx的安装命令

1
pip install https://paddle-wheel.bj.bcebos.com/2.3.0/windows/windows-cpu-mkl-noavx/paddlepaddle-2.3.0-cp38-cp38-win_amd64.whl

  

支持avx的安装命令

1
python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple

  

2.2 PaddleDetection的安装

PaddleDetection的安装相对简单,没有分支。
我这里是在 D:\lusong\ppdetection\ 目录下操作。

 

安装

 

命令行

1
2
3
4
5
6
git clone https://gitee.com/paddlepaddle/PaddleDetection
 
cd PaddleDetection
pip install -r requirements.txt
 
python setup.py install

  

验证

命令行

1
python ppdet/modeling/tests/test_architectures.py

  

 

2.3 数据集

数据集是偶然看到的VOC格式,下载地址为:

http://aistudio.baidu.com/aistudio/projectdetail/1059610

我自己解压缩到 D:\lusong\other\det\HelmetDetection目录。

 

2.4 预训练模型

模型为RestNet50,下载地址为:

https://paddledet.bj.bcebos.com/models/pretrained/ResNet50_vd_ssld_pretrained.pdparams

 

到此,下载部分结束,可以断开网络继续操作。

 

3 训练前处理

3.1 数据集拆分

对数据集完成训练集,验证集,测试集的切分。下面是拆分代码:

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
import os.path as osp
import random
import xml.etree.ElementTree as ET
 
# dataset_dir,数据集所在路径,文件夹层级如下:
{dataset_dir}/
  images/
    xxx.jpg
  annotations/
    xxx.xml
# val_percent,验证百分比
# test_percent,测试百分比
# save_dir,数据集保存到路径(格式:VOC),注意这里和标准的VOC格式是不一样的
{save_dir}/
  train_list.txt
  val_list.txt
  test_list.txt
  labels.txt
# 注意,由上可见:本函数默认dataset_dir和save_dir是同一目录
def split_voc_dataset(dataset_dir, val_percent, test_percent, save_dir):
    # 注意图片目录和标注目录名已全部修改???
    # 检查images目录和annotations目录是否存在
    if not osp.exists(osp.join(dataset_dir, "images")):
        logging.error("\'images\' is not found in {}!".format(dataset_dir))
    if not osp.exists(osp.join(dataset_dir, "annotations")):
        logging.error("\'annotations\' is not found in {}!".format(
            dataset_dir))
    #
    # 获取images目录下所有文件名(images目录及下一层目录)
    all_image_files = list_files(osp.join(dataset_dir, "images"))
    #
    # 元素为 [image_file, anno_name]
    image_anno_list = list()
    # 元素为 anno_name文件中的所有object.name文本(去重)
    label_list = list()
    for image_file in all_image_files:
        if not is_pic(image_file):
            continue
        # 在annotations目录下,寻找image_file对应的anno_name文件,找到后加入image_anno_list
        anno_name = replace_ext(image_file, "xml")
        if osp.exists(osp.join(dataset_dir, "annotations", anno_name)):
            image_anno_list.append([image_file, anno_name])
            # 将anno_name文件中的object子节点的name节点找出来,加入label_list(去重)
            try:
                tree = ET.parse(
                    osp.join(dataset_dir, "annotations", anno_name))
            except:
                raise Exception("文件{}不是一个良构的xml文件,请检查标注文件".format(
                    osp.join(dataset_dir, "annotations", anno_name)))
            objs = tree.findall("object")
            for i, obj in enumerate(objs):
                cname = obj.find('name').text
                if not cname in label_list:
                    label_list.append(cname)
        else:
            logging.error("The annotation file {} doesn't exist!".format(
                anno_name))
    #
    # 打乱image_anno_list后,拆分成train_image_anno_list,val_image_anno_list,test_image_anno_list
    random.shuffle(image_anno_list)
    image_num = len(image_anno_list)
    val_num = int(image_num * val_percent)
    test_num = int(image_num * test_percent)
    train_num = image_num - val_num - test_num
    #
    train_image_anno_list = image_anno_list[:train_num]
    val_image_anno_list = image_anno_list[train_num:train_num + val_num]
    test_image_anno_list = image_anno_list[train_num + val_num:]
    #
    # 创建{save_dir}/train_list.txt 文件
    with open(
            osp.join(save_dir, 'train_list.txt'), mode='w',
            encoding='utf-8') as f:
        for x in train_image_anno_list:
            file = osp.join("images", x[0])
            label = osp.join("annotations", x[1])
            f.write('{} {}\n'.format(file, label))
    #
    # 创建{save_dir}/val_list.txt 文件
    with open(
            osp.join(save_dir, 'val_list.txt'), mode='w',
            encoding='utf-8') as f:
        for x in val_image_anno_list:
            file = osp.join("images", x[0])
            label = osp.join("annotations", x[1])
            f.write('{} {}\n'.format(file, label))
    #
    # 创建{save_dir}/test_list.txt 文件
    if len(test_image_anno_list):
        with open(
                osp.join(save_dir, 'test_list.txt'), mode='w',
                encoding='utf-8') as f:
            for x in test_image_anno_list:
                file = osp.join("images", x[0])
                label = osp.join("annotations", x[1])
                f.write('{} {}\n'.format(file, label))
    #
    # 创建{save_dir}/labels.txt 文件
    with open(
            osp.join(save_dir, 'labels.txt'), mode='w', encoding='utf-8') as f:
        for l in sorted(label_list):
            f.write('{}\n'.format(l))
    #
    return train_num, val_num, test_num
 
 
if __name__ == "__main__":
    # 切分数据集
    split_voc_dataset('PaddleDetection/dataset/MyDataset', 0.2, 0.1, 'PaddleDetection/dataset/MyDataset')

 

运行上面代码完成后,训练集、验证集、测试集分别记录在文件:train_list.txt,val_list.txt,test_list.txt文件中。

 

3.2 数据集的配置

数据集的配置主要是写明训练集/验证集/测试集的文件位置(ppdet和数据集路径见上文所述)。

D:\lusong\ppdetection\PaddleDetection\configs\datasets\voc.yml

dataset_dir路径
该路径下包括anno_path所指文件。无需标准的VOC的两级目录:VOCdevkit/VOC2007(或VOC2012)。

代码(yml)
metric: VOC
map_type: 11point
num_classes: 4

TrainDataset:
  !VOCDataSet
    dataset_dir: D:\lusong\other\det\HelmetDetection
    anno_path: train_list.txt
    label_list: labels.txt
    data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult']

EvalDataset:
  !VOCDataSet
    dataset_dir: D:\lusong\other\det\HelmetDetection
    anno_path: val_list.txt
    label_list: labels.txt
    data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult']

TestDataset:
  !ImageFolder
    anno_path: dataset/voc/test_list.txt

 

4 训练

调用命令行:

1
2
3
4
5
6
7
python -u tools/train.py
 
 -c D:\lusong\ppdetection\PaddleDetection\configs\ppyolo\ppyolo_r50vd_dcn_voc_1.yml
 
 -o use_gpu=false pretrain_weights=D:\lusong\other\det\model\ResNet50_vd_ssld_pretrained.pdparams
 
 --eval

  

4.1 继续训练

有时候会意外或主动中断,如需继续训练的话,调用命令行:

1
2
3
4
5
python -u tools/train.py \
 -c D:\lusong\ppdetection\PaddleDetection\configs\ppyolo\ppyolo_r50vd_dcn_voc_1.yml \
 -o use_gpu=false \
 -r output/ppyolo_r50vd_dcn_voc_1/best_model \
 --eval

  

 

5 推理

中断训练后,项看当前训练的怎么样的话,调用命令行:

1
2
3
4
python -u tools/infer.py
 -c D:\lusong\ppdetection\PaddleDetection\configs\ppyolo\ppyolo_r50vd_dcn_voc_1.yml
 -o use_gpu=false weights=D:\lusong\ppdetection\PaddleDetection\output\ppyolo_r50vd_dcn_voc_1\best_model.pdparams
 --infer_img=D:\lusong\other\det\HelmetDetection\images\hard_hat_workers0.png

  

 

至此,可以启动训练,并在成功保存模型的情况下,执行推理。

 

6 对训练时长的缩减

6.1 修改ppyolo_r50vd_dcn_voc.yml,缩减:训练轮数,batch尺寸,保存时间间隔(轮数)。减少整个训练时长。

  snapshot_epoch: 1
TrainReader:

  batch_size: 2

epoch: 10

6.2 修改数据集文件,缩减:单轮训练图片数量,单轮验证图片数量。减少单轮训练时长。

缩减单轮训练图片数量:编辑train_list.txt文件,一行一个训练样本,根据训练时长整行删除即可。

缩减单轮验证图片数量:同上编辑val_list.txt文件。

 

7 小结
1 简单感受了一下VOC格式,划分的训练集,ppdet的配置方式,调用方式。

2 训练代码还是比较简单,很容易上手。

3 纯时间耗费不起(原训练配置ppdet估计时长为140天左右)。

4 ppdet=2.6有bug,会时不时异常退出,浪费时间巨大。

 

贵阳正值疫情期间,心情有点慌张。

posted on   EpicBlue  阅读(1500)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

点击右上角即可分享
微信分享提示