PaddleSeg实现自动驾驶语义分割

在这里插入图片描述

图像分割套件PaddleSeg全面解析

PaddleSeg——gitee地址

PaddleSeg全流程跑通

本示例的主要流程如下:

  • 准备环境:使用PaddleSeg的软件环境
  • 准备数据:用户如何准备、整理自定义数据集
  • 模型训练:训练配置和启动训练命令
  • 可视化训练过程:使用VDL展示训练过程
  • 模型评估:评估模型效果
  • 模型预测与可视化:使用训练好的模型进行预测,同时对结果进行可视化
  • 模型导出:如何导出可进行部署的模型
  • 模型部署:快速使用Python实现高效部署

1 环境安装

# 克隆PaddleSeg仓库,国内可以直接使用gitee的库
!git clone https://gitee.com/paddlepaddle/PaddleSeg.git

# 安装其他依赖
%cd PaddleSeg
!pip install -r requirements.txt

2 数据准备

2.1 数据介绍

Semantic Segmentation for Self Driving Cars数据地址

CARLA自动驾驶模拟器

该数据集提供通过CARLA自动驾驶汽车模拟器捕获的数据图像和标记语义分割。这些数据是作为Lyft Udacity Challenge的一部分生成的。此数据集可用于训练 ML 算法,以识别图像中汽车、道路等的语义分割。

在这里插入图片描述

该数据有5组1000张图像和相应的标签。本项目合并了AB两组数据作为训练集和验证集。

# 解压数据到PaddleSeg/dataset/文件夹

%cd ~
!mkdir PaddleSeg/dataset/
!unzip -d PaddleSeg/dataset/dataA_B data/data151864/dataA_B.zip

2.2 数据可视化

本数据集是三通道的,只取mask[:,:,0]即第一个通道的值作为label。

%cd ~/PaddleSeg
import pandas as pd
import numpy as np
import random
import os
import matplotlib.pyplot as plt
img_path = 'dataset/dataA_B/images'
mask_path = 'dataset/dataA_B/annotations'

image_list = os.listdir(img_path)
img_name = random.choice(image_list)
img = plt.imread(os.path.join(img_path,img_name))
mask = plt.imread(os.path.join(mask_path,img_name))
fig, axs = plt.subplots(1,2,figsize=(10,5))
axs[0].imshow(img)
axs[1].imshow(mask[:,:,0])
for a in axs:
    a.axis('off')
plt.show()
/home/aistudio/PaddleSeg

在这里插入图片描述

# 输出mask三个通道的值
print(mask.shape)
print("==============================")
print(mask[:,:,0])
print("==============================")
print(mask[:,:,1])
print("==============================")
print(mask[:,:,2])
(600, 800, 3)
==============================
[[0.         0.         0.         ... 0.         0.         0.        ]
 [0.         0.         0.         ... 0.         0.         0.        ]
 [0.         0.         0.         ... 0.         0.         0.        ]
 ...
 [0.03921569 0.03921569 0.03921569 ... 0.03921569 0.03921569 0.03921569]
 [0.03921569 0.03921569 0.03921569 ... 0.03921569 0.03921569 0.03921569]
 [0.03921569 0.03921569 0.03921569 ... 0.03921569 0.03921569 0.03921569]]
==============================
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
==============================
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
#找出掩码中唯一的值,即标签种类数量
np.unique(mask * 255)
array([ 0.,  1.,  2.,  3.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.],
      dtype=float32)
# 标签
labels = ['Unlabeled','Building','Fence','Other',
          'Pedestrian', 'Pole', 'Roadline', 'Road',
          'Sidewalk', 'Vegetation', 'Car','Wall',
          'Traffic sign']
for i in range(13):
    mask = plt.imread('dataset/dataA_B/annotations/02_00_000.png')*255
    #如果等一i就为255其他为0   
    mask = np.where(mask == i, 255, 0)
    #取mask
    mask1 = mask[:,:,0]
    plt.title(f'class: {i} {labels[i]}')
    plt.imshow(mask1)
    plt.show()

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.3 数据处理

PaddleSeg采用单通道的标注图片,每一种像素值代表一种类别,像素标注类别需要从0开始递增,例如0,1,2,3表示有4种类别。

注: 标注图像请使用PNG无损压缩格式的图片。标注类别最多为256类。

以上是PaddleSeg的标注协议,即我们的数据需要满足是单通道的标注图片,所以要将数据变为单通道的灰度图。但针对灰度图不仅只能看见全黑的效果,还存在相应的弊端:

  • 对图像标注后,无法直接观察标注是否正确。
  • 模型测试过程无法直接判断分割的实际效果。

在这里插入图片描述

PaddleSeg支持伪彩色图作为标注图片,在原来的单通道图片基础上,注入调色板。在基本不增加图片大小的基础上,却可以显示出彩色的效果。

同时PaddleSeg也兼容灰度图标注,用户原来的灰度数据集可以不做修改,直接使用。

本项目是将图像转换为灰度图再转换为伪彩色标注图来做处理。

# 将三通道变成单通道。
import os
import os.path as osp
import sys
import numpy as np
from PIL import Image
input = 'dataset/dataA_B/annotations'
# os.walk()方法用于通过在目录树中游走输出在目录中的文件名
for fpath, dirs, fs in os.walk(input):
    print(fpath)
    for f in fs:
        try:
            path = osp.join(fpath, f)
            # _output_dir = fpath.replace(input, '')
            # _output_dir = _output_dir.lstrip(os.path.sep)

            image = Image.open(path)
            image,_,_ = image.split()
            image.save(path)
            
        except:
            continue
    print("已变为单通道!")
dataset/dataA_B/annotations
已变为单通道!
# 转换为单通道灰度图可视化
img_path = 'dataset/dataA_B/images'
mask_path = 'dataset/dataA_B/annotations'

image_list = os.listdir(img_path)
img_name = random.choice(image_list)
img = plt.imread(os.path.join(img_path,img_name))
mask = plt.imread(os.path.join(mask_path,img_name))
fig, axs = plt.subplots(1,2,figsize=(10,5))
axs[0].imshow(img)
axs[1].imshow(mask)
for a in axs:
    a.axis('off')
plt.show()

在这里插入图片描述

灰度标注转换为伪彩色标注

可以直接使用PaddleSeg提供的转换工具。

%cd ~/PaddleSeg
!python tools/gray2pseudo_color.py dataset/dataA_B/annotations/ dataset/dataA_B/annotations/

img_path = 'dataset/dataA_B/images'
mask_path = 'dataset/dataA_B/annotations'

image_list = os.listdir(img_path)
img_name = random.choice(image_list)
img = plt.imread(os.path.join(img_path,img_name))
mask = plt.imread(os.path.join(mask_path,img_name))
fig, axs = plt.subplots(1,2,figsize=(10,5))
axs[0].imshow(img)
axs[1].imshow(mask)
for a in axs:
    a.axis('off')
plt.show()

在这里插入图片描述

2.4 数据集划分

在这里插入图片描述

以下为数据的种类标签,即生成labels.txt的值。

Unlabeled
Building
Fence
Other
Pedestrian
Pole
Roadline
Road
Sidewalk
Vegetation
Car
Wall
Traffic sign
# 使用PaddleSeg提供的划分数据集的工具
%cd ~/PaddleSeg
!python tools/split_dataset_list.py dataset/dataA_B images annotations --split 0.7 0.3 0 --format png png --label_class 'Unlabeled' 'Building' 'Fence' 'Other' 'Pedestrian' 'Pole' 'Roadline' 'Road' 'Sidewalk' 'Vegetation' 'Car' 'Wall' 'Traffic sign'

3 模型训练

3.1 PP-LiteSeg模型介绍

本示例选择PP-LiteSeg模型进行训练。

PP-LiteSeg是PaddleSeg团队自研的轻量化模型,在Cityscapes数据集上超越其他模型,实现最优的精度和速度平衡。 具体而言,PP-LiteSeg模型沿用编解码架构,设计灵活的Decoder模块(FLD)、统一注意力融合模块(UAFM)和简易PPM上下文模块(SPPM),实现高精度和高效率的实时语义分割。

PP-LiteSeg模型的结构如下图。更多详细介绍,请参考链接

在这里插入图片描述

3.2 配置文件详解

PaddleSeg提供配置化驱动进行模型训练、测试和预测等,配置文件是其中的关键。

PaddleSeg的配置文件包括超参、训练数据集、验证数据集、优化器、损失函数、模型等信息。所有的配置文件在PaddleSeg/configs文件夹下面。大家可以灵活修改配置文件的内容,如自定义模型使用的骨干网络、模型使用的损失函数以及关于网络结构等配置,自定义配置数据处理的策略,如改变尺寸、归一化和翻转等数据增强的策略。

重点参数说明:

  • 在PaddleSeg的配置文件给出的学习率中,除了"pp_liteseg_optic_disc_512x512_1k.yml"中为单卡学习率外,其余配置文件中均为4卡的学习率,如果用户是单卡训练,则学习率设置应变成原来的1/4。
  • 在PaddleSeg中的配置文件,给出了多种损失函数:CrossEntropy Loss、BootstrappedCrossEntropy Loss、Dice Loss、BCE Loss、OhemCrossEntropyLoss、RelaxBoundaryLoss、OhemEdgeAttentionLoss、Lovasz Hinge Loss、Lovasz Softmax Loss,用户可根据自身需求进行更改。
  • 配置文件解读如下。
batch_size: 4  #设定batch_size的值即为迭代一次送入网络的图片数量,一般显卡显存越大,batch_size的值可以越大
iters: 1000    #模型迭代的次数

train_dataset:  #训练数据设置
  type: Dataset #数据集名字
  dataset_root: data/optic_disc_seg #数据集路径
  train_path: data/optic_disc_seg/train_list.txt  #数据集中用于训练的标识文件
  num_classes: 2  #指定目标的类别个数(背景也算为一类)
  mode: train #表示用于训练
  transforms: #数据预处理/增强的方式
    - type: ResizeStepScaling #将原始图像和标注图像随机缩放为0.5~2.0倍
      min_scale_factor: 0.5
      max_scale_factor: 2.0
      scale_step_size: 0.25
    - type: RandomPaddingCrop #从原始图像和标注图像中随机裁剪512x512大小
      crop_size: [512, 512]
    - type: RandomHorizontalFlip  #采用水平反转的方式进行数据增强
    - type: RandomDistort #亮度、对比度、饱和度随机变动
      brightness_range: 0.5
      contrast_range: 0.5
      saturation_range: 0.5
    - type: Normalize #将图像归一化

val_dataset:  #验证数据设置
  type: Dataset #数据集名字
  dataset_root: data/optic_disc_seg #数据集路径
  val_path: data/optic_disc_seg/val_list.txt  #数据集中用于验证的标识文件
  num_classes: 2  #指定目标的类别个数(背景也算为一类)
  mode: val #表示用于验证
  transforms: #数据预处理/增强的方式
    - type: Normalize #图像进行归一化

optimizer: #设定优化器的类型
  type: sgd #采用SGD(Stochastic Gradient Descent)随机梯度下降方法为优化器
  momentum: 0.9 #动量
  weight_decay: 4.0e-5 #权值衰减,使用的目的是防止过拟合

lr_scheduler: # 学习率的相关设置
  type: PolynomialDecay # 一种学习率类型。共支持12种策略
  learning_rate: 0.01
  power: 0.9
  end_lr: 0

loss: #设定损失函数的类型
  types:
    - type: CrossEntropyLoss  #损失函数类型
  coef: [1, 1, 1] # PP-LiteSeg有一个主loss和两个辅助loss,coef表示权重: total_loss = coef_1 * loss_1 + .... + coef_n * loss_n

model:  #模型说明
  type: PPLiteSeg  #设定模型类别
  backbone:  # 设定模型的backbone,包括名字和预训练权重
    type: STDC2
    pretrained: https://bj.bcebos.com/paddleseg/dygraph/PP_STDCNet2.tar.gz

训练前要修改下方配置文件才能运行 !!!!

我们的配置,使用的configs/pp_liteseg/pp_liteseg_stdc1_camvid_960x720_10k.yml文件,并修改了数据配置(替换文件的相应部分即可)。

train_dataset:
  type: Dataset
  dataset_root: dataset/dataA_B
  num_classes: 13
  mode: train
  train_path: dataset/dataA_B/train.txt
  transforms:
    - type: ResizeStepScaling
      min_scale_factor: 0.5
      max_scale_factor: 2.5
      scale_step_size: 0.25
    - type: RandomPaddingCrop
      crop_size: [960, 720]
    - type: RandomHorizontalFlip
    - type: RandomDistort
      brightness_range: 0.5
      contrast_range: 0.5
      saturation_range: 0.5
    - type: Normalize

val_dataset:
  type: Dataset
  dataset_root: dataset/dataA_B
  num_classes: 13
  mode: val
  val_path: dataset/dataA_B/val.txt
  transforms:
    - type: Normalize

主要关注的参数:

  • type的参数是Dataset,代表的是建议的数据格式;
  • dataset_root路径为包含label和image所在的路径;在示例中为:- - dataset_root: dataset/optic_disc_seg
  • train_path为txt的路径;在示例中为:train_path: dataset/optic_disc_seg/train_list.txt
  • num_classes为类别(背景也算为一类);
  • transform是对数据的预处理的策略,用户可根据自己的实际需要改动

3.3 训练

训练参数解析:

参数名用途是否必选项默认值
iters训练迭代次数配置文件中指定值
batch_size单卡batch size配置文件中指定值
learning_rate初始学习率配置文件中指定值
config配置文件-
save_dir模型和visualdl日志文件的保存根路径output
num_workers用于异步读取数据的进程数量, 大于等于1时开启子进程读取数据0
use_vdl是否开启visualdl记录训练数据
save_interval模型保存的间隔步数1000
do_eval是否在保存模型时启动评估, 启动时将会根据mIoU保存最佳模型至best_model
log_iters打印日志的间隔步数10
resume_model恢复训练模型路径,如:output/iter_1000None
keep_checkpoint_max最新模型保存个数5

训练后的模型参数在 /work 文件夹下

# 修改好配置文件后才能运行。
%cd ~/PaddleSeg
!export CUDA_VISIBLE_DEVICES=0 
!python train.py \
       --config configs/pp_liteseg/pp_liteseg_stdc1_camvid_960x720_10k.yml \
       --do_eval \
       --use_vdl \
       --save_interval 500 \
       --save_dir output

4 可视化

在这里插入图片描述

在这里插入图片描述

5 模型评估

!python val.py \
       --config configs/pp_liteseg/pp_liteseg_stdc1_camvid_960x720_10k.yml \
       --model_path output/best_model/model.pdparams

在图像分割领域中,评估模型质量主要是通过三个指标进行判断,准确率(acc)、平均交并比(Mean Intersection over Union,简称mIoU)、Kappa系数

  • 准确率:指类别预测正确的像素占总像素的比例,准确率越高模型质量越好。
  • 平均交并比:对每个类别数据集单独进行推理计算,计算出的预测区域和实际区域交集除以预测区域和实际区域的并集,然后将所有类别得到的结果取平均。在本例中,正常情况下模型在验证集上的mIoU指标值会达到0.80以上,显示信息示例如下所示,第3行的mIoU=0.8526即为mIoU。
  • Kappa系数:一个用于一致性检验的指标,可以用于衡量分类的效果。kappa系数的计算是基于混淆矩阵的,取值为-1到1之间,通常大于0。其公式如下所示,P0P_0P0为分类器的准确率,PeP_eP**e为随机分类器的准确率。Kappa系数越高模型质量越好。

随着评估脚本的运行,最终打印的评估日志如下。

2022-06-29 10:53:04 [INFO]	[EVAL] #Images: 600 mIoU: 0.7103 Acc: 0.9566 Kappa: 0.9463 Dice: 0.8022
2022-06-29 10:53:04 [INFO]	[EVAL] Class IoU: 
[0.9473 0.9162 0.4943 0.6247 0.1106 0.5114 0.6477 0.9585 0.8975 0.8421
 0.969  0.7128 0.6018]
2022-06-29 10:53:04 [INFO]	[EVAL] Class Precision: 
[0.9755 0.9618 0.7631 0.7762 0.8018 0.8356 0.8263 0.9765 0.9447 0.9007
 0.9738 0.8861 0.8673]
2022-06-29 10:53:04 [INFO]	[EVAL] Class Recall: 
[0.9703 0.9507 0.5839 0.7619 0.1137 0.5687 0.7499 0.9811 0.9473 0.9283
 0.9949 0.7848 0.6628]

6 模型预测与可视化

除了分析模型的IOU、ACC和Kappa指标之外,我们还可以查阅一些具体样本的切割样本效果,从Bad Case启发进一步优化的思路。

predict.py脚本是专门用来可视化预测案例的,命令格式如下所示

!python predict.py \
       --config configs/pp_liteseg/pp_liteseg_stdc1_camvid_960x720_10k.yml \
       --model_path output/best_model/model.pdparams \
       --image_path dataset/dataA_B/images/02_00_063.png\
       --save_dir output/result

可视化:

在这里插入图片描述

7 个人介绍

CSDN地址:https://blog.csdn.net/weixin_43267897?spm=1001.2101.3001.5343

Github地址:https://github.com/KHB1698

AI Studio地址:https://aistudio.baidu.com/aistudio/personalcenter/thirdview/791590

此文仅为搬运,原作链接:https://aistudio.baidu.com/aistudio/projectdetail/4203976

Logo

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

更多推荐