PaddleX:道路裂缝检测

  • 使用EasyDL标注部分道路裂缝数据,转换为PaddleX使用的VOC格式
  • 使用PPYOLOV2模型进行训练

一、数据处理

1. PaddleX安装及数据集解压

! pip install -q paddlex
! mkdir -p data/dataset
# ! unzip -oq data/data109050/India.zip -d data/dataset  # 公开数据集
! unzip -oq data/data113986/RC2V1.zip -d data/dataset  # 从EasyDL标注的数据

2. EasyDL json转VOC xml

from convert import Batch2Xmls


easydl_folder = "data/dataset/DatasetId_251670_1635398672"
save_path = "data/dataset/pdx_data"
Batch2Xmls(easydl_folder, save_path)
100%|██████████| 812/812 [00:01<00:00, 559.98it/s]

3. 转为PaddleX数据组织格式

  • 划分数据集
  • 生成标签列表
import os
import os.path as osp
import random
from tqdm import tqdm
import xml.dom.minidom


def read_xml(xml_path, names):
    try:
        dom = xml.dom.minidom.parse(xml_path)  # 打开XML文件
        collection = dom.documentElement  # 获取元素对象
        object_list = collection.getElementsByTagName("object")  # 获取标签名信息
        for obj in object_list:
            name = obj.getElementsByTagName('name')[0].childNodes[0].data
            if name not in names:
                names.append(name)
    except:
        return

img_folder_path = "data/dataset/pdx_data/images"
img_names = os.listdir(img_folder_path)
random.seed(2)
random.shuffle(img_names)
labels = []

with open("data/dataset/pdx_data/train_list.txt", "w") as tf:
    with open("data/dataset/pdx_data/eval_list.txt", "w") as ef:
        for idx, ima_name in tqdm(enumerate(img_names)):
            img_path = osp.join(img_folder_path, ima_name)
            xml_path = img_path.replace("images", "annotations").replace(".jpg", ".xml")  # annotations/xmls
            if osp.exists(img_path) and osp.exists(xml_path):
                read_xml(xml_path, labels)
                img_path = img_path.replace("data/dataset/pdx_data/", "")
                xml_path = xml_path.replace("data/dataset/pdx_data/", "")
                if idx % 10 == 0:
                    ef.write(img_path + " " + xml_path + "\n")
                else:
                    tf.write(img_path + " " + xml_path + "\n")

with open("data/dataset/pdx_data/labels.txt", "w") as lf:
    for lab in labels:
        lf.write(lab + "\n")
422it [00:00, 3470.44it/s]

4. 统计mean和std

  • 公开数据集太大了,抽样统计的
# import os
# import cv2
# import numpy as np
# import random
# from tqdm import tqdm


# means, stdevs = [], []
# img_list = []
# imgs_path = 'data/dataset/pdx_data/images'
# imgs_name = os.listdir(imgs_path)
# random.shuffle(imgs_name)

# for idx, name in tqdm(enumerate(imgs_name)):
#     img = cv2.cvtColor(cv2.imread(os.path.join(imgs_path, name)), cv2.COLOR_BGR2RGB)
#     img = img[:, :, :, np.newaxis]
#     # if idx % 10 == 0:  # 内存不够,抽样
#     #     img_list.append(img)
#     img_list.append(img)
    
# imgs = np.concatenate(img_list, axis=-1)
# imgs = imgs.astype(np.float32) / 255.

# for i in tqdm(range(3)):
#     pixels = imgs[:, :, i, :].ravel()  # 拉成一行
#     means.append(np.mean(pixels))
#     stdevs.append(np.std(pixels))
# print(means, stdevs)
422it [00:18, 23.32it/s]
100%|██████████| 3/3 [00:27<00:00,  9.05s/it]

[0.40158695, 0.43556893, 0.507324] [0.19307534, 0.19843009, 0.2915112]
归一化

India

mean: [0.51279986, 0.52223563, 0.52388006]
std: [0.26084045, 0.26875973, 0.29285163]

RC2_V1

mean: [0.40158695, 0.43556893, 0.507324]
std: [0.19307534, 0.19843009, 0.2915112]

5. 锚框聚类

# from anchor import load_one_info, get_kmeans

# result = []
# xml_folder = "data/dataset/pdx_data/annotations"
# for name in os.listdir(xml_folder):  
#     result.extend(load_one_info(name, xml_folder))
# result = np.array(result)
# anchors, ave_iou = get_kmeans(result, 9)
# anchor_string = ''
# anchor_sizes = []
# for anchor in anchors:
#     anchor_string += '{},{}, '.format(anchor[0], anchor[1])
#     anchor_sizes.append([anchor[0], anchor[1]])
# anchor_string = anchor_string[:-2]

# print('anchors are:')
# print(anchor_string)
# print('the average iou is:')
# print(ave_iou)
anchors are:
81,20, 243,20, 138,37, 404,27, 565,20, 259,77, 670,30, 1141,31, 444,177
the average iou is:
0.7248688626535296
锚框

RC2_V1

anchors are:81,20, 243,20, 138,37, 404,27, 565,20, 259,77, 670,30, 1141,31, 444,177
the average iou is:0.7248688626535296

6. 准备数据

import paddlex as pdx
from paddlex import transforms as T


train_transforms = T.Compose([
    T.MixupImage(mixup_epoch=-1), 
    T.RandomDistort(),
    T.RandomExpand(), 
    T.RandomCrop(),
    T.RandomHorizontalFlip(),
    T.Resize(target_size=(1088, 1920), interp='RANDOM'),
    # T.BatchRandomResize(
    #     target_sizes=[416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736],
    #     interp='RANDOM'), 
    T.Normalize(mean=[0.40158695, 0.43556893, 0.507324], std=[0.19307534, 0.19843009, 0.2915112])])
eval_transforms = T.Compose([
    T.Resize(target_size=(1088, 1920), interp='CUBIC'), 
    T.Normalize(mean=[0.40158695, 0.43556893, 0.507324], std=[0.19307534, 0.19843009, 0.2915112])])

train_dataset = pdx.datasets.VOCDetection(
    data_dir='data/dataset/pdx_data',
    file_list='data/dataset/pdx_data/train_list.txt',
    label_list='data/dataset/pdx_data/labels.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.VOCDetection(
    data_dir='data/dataset/pdx_data',
    file_list='data/dataset/pdx_data/eval_list.txt',
    label_list='data/dataset/pdx_data/labels.txt',
    transforms=eval_transforms)
2021-10-29 17:34:42 [INFO]	Starting to read file list from dataset...
2021-10-29 17:34:42 [INFO]	352 samples in file data/dataset/pdx_data/train_list.txt, including 352 positive samples and 0 negative samples.
creating index...
index created!
2021-10-29 17:34:42 [INFO]	Starting to read file list from dataset...
2021-10-29 17:34:42 [INFO]	38 samples in file data/dataset/pdx_data/eval_list.txt, including 38 positive samples and 0 negative samples.
creating index...
index created!

二、训练

  • 先使用过公开数据集训练,然后将模型作为预训练模型
num_classes = len(train_dataset.labels)
model = pdx.det.PPYOLOv2(num_classes=num_classes, anchors=
    [[82, 20], [244, 20], [138, 38], [404, 28], [566, 20], [260, 78], [670, 30], [1142, 32], [444, 178]])

model.train(
    num_epochs=200,
    train_dataset=train_dataset,
    train_batch_size=2,
    eval_dataset=eval_dataset,
    pretrain_weights='output_rc2_v1/best_model_v1/model.pdparams',
    learning_rate=3e-6,
    warmup_steps=20,
    warmup_start_lr=1e-8,
    lr_decay_epochs=[30, 112],
    lr_decay_gamma=.5,
    save_interval_epochs=40,
    save_dir='output_rc2_v1',
    use_vdl=True)

三、预测

import paddlex as pdx
from paddlex import transforms as T
import matplotlib.pyplot as plt

%matplotlib inline


eval_transforms = T.Compose([
    T.Resize(target_size=(1088, 1920), interp='CUBIC'), 
    T.Normalize(mean=[0.40158695, 0.43556893, 0.507324], std=[0.19307534, 0.19843009, 0.2915112])])

model = pdx.load_model('output_rc2_v1/best_model')
image_name = 'data/dataset/pdx_data/images/D_0002388.jpg'
result = model.predict(image_name)
pred = pdx.det.visualize(image_name, result, threshold=0.5, save_dir=None)
pred = pred[:, :, ::-1]  # 2RGB
plt.figure(figsize=(10, 10))
dict(image_name)
pred = pdx.det.visualize(image_name, result, threshold=0.5, save_dir=None)
pred = pred[:, :, ::-1]  # 2RGB
plt.figure(figsize=(10, 10))
plt.imshow(pred)
2021-10-30 00:09:25 [INFO]	Model[PPYOLOv2] loaded.





<matplotlib.image.AxesImage at 0x7f24f87cf1d0>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jtJbd1yE-1637193156413)(output_20_2.png)]

四、导出inference预测*

! paddlex --export_inference --model_dir=output_rc2_v1/best_model/ --save_dir=infer_rc2_v1 --fixed_input_shape=[1,3,1088,1920]
Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐