PaddleSeg训练推理及模型转换全流程

news2024/12/28 3:56:34

文章目录

  • 1、数据准备
    • 1.1 数据标注
    • 1.2 数据导出
    • 1.3 标签较验
    • 1.4 数据集整理
    • 1.5 标签可视化
  • 2、 模型训练
  • 3、模型验证
  • 4、模型推理
  • 5、模型导出
  • 6、导出文件的推理
  • 7、将模型转换成onnx
  • 8、使用onnx进行推理

本文记录一下使用paddleseg进行语议分割模型对人体进行分割的使用流程。事实上,做算法是脱离框架的,用啥实现都何以,但到2024了,一个点是如果有预训练模型,那就用起来;另一个是放下内心对于不同框架的喜好,结束束battle,什么 tensorflow,pytorch,paddlepaddle,keras,jax。。。,重心集中到算法和自己的需求上。需求无非是两个,一个是研究,就是researcher,需要发文章,那就看文章用什么做的,我们就跟着用什么,不会的api现场查,用chatgpt生成都可以;框架同质化的今天,真是一通百通,做到能查能用即可,道理都一样; 另一个点就是落地,engineer,最后肯定是用onnx,tensorrt,openvino…布署到相应的硬件上,更多的是拿来主义,跑通,在自己特定的场景上生效就可以。在跑通过程中,可以适当对原理进行探纠。整个过程可以先看看https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.9/docs/whole_process_cn.md

本文主打一个细致,快速训练模型,时间长了也怕忘记,感觉有帮助的话请点个赞。

1、数据准备

1.1 数据标注

用标注神器x-anylabeling,就是咱国产的,功能强大特别好用。labelimg,labelme都用过,相比差多了。如图:
在这里插入图片描述

那说一下它的好处,就是可以用官方的训练好的模型来直接跑图,不用人标,只要后期调一下错的就行。我用的是 combining GroundingDINO with HQ-SAM to achieve sota zero-shot high-quality predictions,就是dino检测+sam分割,效果比人标的好。也可以用自己训练好的yolov8-seg模型来做为预训练模型去自动标注数据。
对标注的理解,也可以参考contrib/PaddleLabel/doc/CN/project/semantic_segmentation.md:
在这里插入图片描述
https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.9/docs/data/marker/marker_cn.md 这个也要看。
就是说paddleseg是要用灰度标注的,但是支持伪彩色标注的。
在这里插入图片描述

1.2 数据导出

关于数据导出,就参考https://github.com/CVHub520/X-AnyLabeling/blob/main/docs/zh_cn/user_guide.md。这里吧。
paddleseg支持的标签是uint8,8bit 灰度图,0默认是表示 background,255表示无作用(应该是为了方便可视化,图像加pad这类操作,不参加loss计算)。1-254 共254个类是我们可以用的(现在不知道超过这个范围怎么办)。
在这里插入图片描述

导出后的图保存在与图片同路径下的mask文件夹下,肉眼看不了,就是全黑。

1.3 标签较验

导出的标签要通过可视化来看是否标注正确。
tools/data 下边有两个一个是gray2pseudo_color.py,另一个是visualize_annotation.py。前一个是转成伪彩色来看,后一个相对麻烦,后边再说。
在这里插入图片描述
生成图片后,看看效果,我这里遇到的一个问题就是dino+sam标注,因为dino检测框多了,所以会有重复的部分,正常操作应该是要在x-anylbeling中删除,但太没没删尽,或者这个单分类的分割任务是不用删的。
在这里插入图片描述
person标签本来是1的,但重叠部分是会变成2,写代码把所有2的部分变成1就可以。
在这里插入图片描述
背景是红色的,1是绿色,2是黄。
这就是看伪彩色的意义。

1.4 数据集整理

官方的结构是这样:
在这里插入图片描述
这里我的准备是这样的:

datasets
	|
	|-----images
	|          |
	|          |----a
	|          |----b
	|          |----c
	|
	|----labels
	|			|---a
	|			|---b
	|			|---c
	 			

a,b,c是三个不同数据的来源,images 下边是原图,labels 同名的png标签。
接着生成各个数据集的训练和验证数据集,用如下代码:

Description: 主要是用来生成各个训练集的训练和测试列表
path_root
    images
        a
        b
    labels
        a
        b
将生成a_train.txt  b_train.txt ,这里把所有的数据全做成训练集就ok,不浪费数据;验证集把训练集复制一份就好了,不用担心过拟合,不用担心的
'''
import os
from tqdm import tqdm


path_root="/home/tl/PaddleSeg29/datasets"  #最好上一个绝对路径
img_path = os.path.join(path_root,"images")
lb_path = os.path.join(path_root,"labels")

image_names=os.listdir(img_path)
label_names=os.listdir(lb_path)

#取个交集,更加安全
dataset_names = list(set(image_names) & set(label_names))
#接着对各个数据集分别生成训练列表
for i,dataset in enumerate(dataset_names):
    print(f"start to do dataset:{dataset}")
    dataset_images=[i for i in os.listdir(os.path.join(img_path,dataset)) if os.path.splitext(i.lower())[1] in [".png",".jpg",".jpeg"]] #不做过多的数据集质量较验
    # dataset_labels=os.listdir(os.path.join(img_path,dataset))
    lines=[]
    for imgname in tqdm(dataset_images):
        labelname = os.path.splitext(imgname)[0]+".png" #注意这个后缀,正常都是小写png,如果自己有特别的
        line = os.path.join("images",dataset,imgname)+" "+os.path.join("labels",dataset,labelname)+"\n"
        lines.append(line)
    save_name=os.path.join(path_root,f"{dataset}_train.txt")
    with open(save_name,"w") as f:
        f.writelines(lines)
print("Done")

接着,生成最图训练所用的数据列表:
在这里插入图片描述

cat a_train.txt b_train.txt c_train.txt > train.txt
cat b_train.txt c_train.txt > val.txt

每一行都是:

images/a/1.jpg labels/a/1.png
....
images/b/1.jpg labels/b/1.png
...
images/c/1.jpg labels/c/1.png

1.5 标签可视化

这次用到的是tools/data/visualize_annotation.py

python3 tools/data/visualize_annotation.py --file_path ./dataset/MT_dataset/train.txt --save_dir ./show/

效果是这样的:
在这里插入图片描述
这个脚本还可以同时把predict的图显示出来,但要把预测的mask.png放到与原图同一个文件件下,这里就没做,具体看代码。

2、 模型训练

https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.9/contrib/PP-HumanSeg/README_cn.md
因为是训练人像分割,就用pphuman了,配置文件在contrib/config/PPHUmanSeg中,默认的config下边也有好多的模型。
配置文件保存在./configs目录下,如下。配置文件中,已经通过pretrained设置好预训练权重的路径。

configs
├── human_pp_humansegv1_lite.yml
├── human_pp_humansegv2_lite.yml
├── human_pp_humansegv1_mobile.yml
├── human_pp_humansegv2_mobile.yml
├── human_pp_humansegv1_server.yml
执行如下命令,进行模型微调(大家需要根据实际情况修改配置文件中的超参)。模型训练的详细文档,请参考链接。

export CUDA_VISIBLE_DEVICES=0 # Linux下设置1张可用的卡

# set CUDA_VISIBLE_DEVICES=0  # Windows下设置1张可用的卡
python tools/train.py \
  --config configs/human_pp_humansegv2_lite.yml \
  --save_dir output/human_pp_humansegv2_lite \
  --save_interval 100 --do_eval --use_vdl

v1-lite 大概2M,v2-lite 4M v1 mobile 13M v2 mobile 20M
按需求来取。
配置文件和预训练模型都可以拿来用,如下:

batch_size: 256
iters: 2000

train_dataset:
 type: Dataset
 dataset_root: /home/tl/PaddleSeg29/datasets
 train_path: /home/tl/PaddleSeg29/datasets/train.txt
 num_classes: 2
 transforms:
   - type: Resize
     target_size: [192, 192]
   - type: ResizeStepScaling
     scale_step_size: 0
   - type: RandomRotation
   - type: RandomPaddingCrop
     crop_size: [192, 192]
   - type: RandomHorizontalFlip
   - type: RandomDistort
   - type: RandomBlur
     prob: 0.3
   - type: Normalize
 mode: train

val_dataset:
 type: Dataset
 dataset_root: /home/tl/PaddleSeg29/datasets
 val_path:  /home/tl/PaddleSeg29/datasets/val.txt
 num_classes: 2
 transforms:
   - type: Resize
     target_size: [192, 192]
   - type: Normalize
 mode: val

export:
 transforms:
   - type: Resize
     target_size: [192, 192]
   - type: Normalize


optimizer:
 type: sgd
 momentum: 0.9
 weight_decay: 0.0005

lr_scheduler:
 type: PolynomialDecay
 learning_rate: 0.0005
 end_lr: 0
 power: 0.9

loss:
 types:
   - type: MixedLoss
     losses:
       - type: CrossEntropyLoss
       - type: LovaszSoftmaxLoss
     coef: [0.8, 0.2]
 coef: [1]

model:
 type: PPHumanSegLite
 align_corners: False
 num_classes: 2
 #pretrained: /home/tl/PaddleSeg29/models/segv1-lite/human_pp_humansegv1_lite_192x192_pretrained/model.pdparams
 pretrained: /home/tl/PaddleSeg29/output/seglitev1/best_model/model.pdparams

batch-size iters 看自己的显卡大小来改;学习率也可以改,各参数的意义可以参看:https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.9/docs/whole_process_cn.md,路径的改动:
在这里插入图片描述
最后读取图片,大致是dataset_root分别加上txt文件里的两部分来读取图和target.
模型保存结果为:
在这里插入图片描述

3、模型验证

这步就不做了,因为在训练过程做过。如查要做,可以参看:
https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.9/docs/evaluation/evaluate_cn.md
命令就是:

python tools/val.py \
      --config configs/quick_start/pp_liteseg_optic_disc_512x512_1k.yml \
      --model_path output/iter_1000/model.pdparams

在这里插入图片描述
这里我们只关注我们关注的类别,分别有Iou,精确率和召回率。

4、模型推理

命令行如下:

python tools/predict.py \
  --config configs/human_pp_humansegv2_lite.yml \
  --model_path pretrained_models/human_pp_humansegv2_lite_192x192_pretrained/model.pdparams \
  --image_path data/images/human.jpg \
  --save_dir ./data/images_result

在这里插入图片描述
added_prediction:
在这里插入图片描述
pseudo_color_prediction:
在这里插入图片描述

5、模型导出

导出方便部署,命令行如下:

python tools/export.py \
  --config configs/human_pp_humansegv2_lite.yml \
  --model_path pretrained_models/human_pp_humansegv2_lite_192x192_pretrained/model.pdparams \
  --save_dir output/human_pp_humansegv2_lite \
  --without_argmax \
  --with_softmax

更多的需要参照这个文档:https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.9/docs/model_export_cn.md
在这里插入图片描述
因为后处理,只有一个算子,所以一个都不要,我们在外边处理。
导出文件为:
在这里插入图片描述

6、导出文件的推理

导出文件推理,导出模型时的后处理要加argmax,
推理命令为:

python deploy/python/infer.py --config output/inference_model/mobilev2_192_argx/deploy.yaml --image_path human1.jpg --save_dir ./show/out4

输出结果是伪彩色图,大小是192x192和输入一样大小。并没有转回到原图。
在这里插入图片描述

7、将模型转换成onnx

需要用使用paddle2onnx这个工具,转换命令参照这里:
https://github.com/PaddlePaddle/Paddle2ONNX,命令行如下:

paddle2onnx --model_dir saved_inference_model \
            --model_filename model.pdmodel \
            --params_filename model.pdiparams \
            --save_file model.onnx

接着对onnx 进行简化,要用到onnxsim这个包:

python -m onnxsim litev1_192.onnx litev1_sim_192.onnx

在这里插入图片描述
这里作了四个模型,分别如图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从精度和性能来看。选合适的来用。
onnx相比是更加重要的,因为我们通常是基于onnx进行各种转换再部署到相应的硬件上的。

8、使用onnx进行推理

这部分代码是从predict.py中按照处理流程,结合deeploy/python中的部分代码及github自己整理的,c++的就不搞了,上个Python的.

'''
Author: tianliang
Date: 2024-05-14 16:33:15
LastEditors: tianliang
LastEditTime: 2024-05-16 16:25:47
FilePath: /deeplabv3/main.py
Description: 
'''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import copy
import argparse
import cv2
import numpy as np
import onnxruntime

class mobilev1seg:
    def __init__(self):

        # Initialize model
        self.onnx_session = onnxruntime.InferenceSession("/home/tl/deeplabv3/mobv1_save_shape_sim.onnx")
        self.input_name = self.onnx_session.get_inputs()[0].name
        self.output_name = self.onnx_session.get_outputs()[0].name

        self.input_shape = self.onnx_session.get_inputs()[0].shape
        self.input_height = self.input_shape[2]
        self.input_width = self.input_shape[3]
        self.mean = np.array([0,0,0], dtype=np.float32).reshape(1,1,3)
        self.std = np.array([1.,1.,1.], dtype=np.float32).reshape(1,1,3)
    def prepare_input(self, image):
        input_image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
        input_image = cv2.resize(input_image, dsize=(self.input_width, self.input_height),interpolation=cv2.INTER_LINEAR)
        input_image = (input_image.astype(np.float32) / 255.0 - self.mean) / self.std
        input_image = input_image.transpose(2, 0, 1)
        input_image = np.expand_dims(input_image, axis=0)
        return input_image


    def detect_argmax(self, image):
        input_image = self.prepare_input(image)

        # Perform inference on the image
        result = self.onnx_session.run([self.output_name], {self.input_name: input_image})

        # Post process:squeeze
        segmentation_map = result[0] # 1x2x384x384
        segmentation_map = np.squeeze(segmentation_map) #2x384x384
        segmentation_map = np.transpose(segmentation_map,(1,2,0)) #384x384x2
        image_width, image_height = image.shape[1], image.shape[0] #原图形状
        segmentation_map = cv2.resize(
            segmentation_map,
            dsize=(image_width, image_height),
            interpolation=cv2.INTER_LINEAR,
        )  #双线性插值回到原图
        pred = np.argmax(segmentation_map,axis=-1) # OrigH x OrigW x 2 -> OrigH x OrigW 值就是0,1
        pred = pred.astype("uint8")
        #可视化
        dst_image = copy.deepcopy(image)
        contours,hierarchy= cv2.findContours(pred,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        #for c in contours:
        if len(contours)>0:
            cv2.drawContours(dst_image, contours, -1, (0, 255, 0), 1)
        #contours就是所有的点的坐标
        return dst_image


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--imgpath', type=str, default='3.jpg', help="image path")
    parser.add_argument('--use_video', type=int, default=0, help="if use video")
    args = parser.parse_args()
    save=True
    segmentor = mobilev1seg()
    if args.use_video != 1:
        srcimg = cv2.imread(args.imgpath,cv2.IMREAD_COLOR)
        # Detect Objects
        dstimg = segmentor.detect_argmax(srcimg)
        if save:
            cv2.imwrite("dst.jpg",dstimg)
        else:
            winName = 'Seg in ONNXRuntime'
            cv2.namedWindow(winName, 0)
            cv2.imshow(winName, dstimg)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
    else:
        cap = cv2.VideoCapture(0)  ###也可以是视频文件
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            dstimg = segmentor.detect(frame)
            key = cv2.waitKey(1)
            if key == 27:  # ESC
                break
            cv2.imshow('Seg Demo', dstimg)
        cap.release()
        cv2.destroyAllWindows()

对于多分类的,后处理可以适当自己再处理一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1697050.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自然资源-各级国土空间总体规划的审查要点及流程总结

自然资源-各级国土空间总体规划的审查要点及流程总结 国土空间规划是对一定区域国土空间开发保护在空间和时间上作出的安排,包括总体规划、详细规划和相关专项规划。 国土空间规划管理是国土空间规划中重要的一环。中共中央、国务院发布《关于建立国土空间规划体系…

数据与结构--AVL树

目录 AVL树的概念 AVL树的性质 AVL树结点的定义 AVL树的插入 AVL树的旋转 左单旋 右单旋 左右双旋 右左单旋 AVL树的验证 AVL树的查找 AVL树的修改 AVL树的删除 AVL树的概念 二叉搜索树虽然可以提高我们查找数据的效率,但如果插入二叉搜索树的数据是…

福昕PDF使用技巧

因为突然间学校的企业版WPS突然很多功能就不能使用了,所以转向福昕PDF。 一、合并文件 添加需要合并的文件,可以使用ctrla等方式全选 找到最上方的“合并文件” 二、文本注释

linux中最常用的文件管理命令

linux中最常用的文件管理命令 linux中最常用的文件管理命令最常用的且没有之一的 ls命令格式不加任何参数使用-l显示更多细节使用-t按照时间排序使用-r按照时间逆序使用-S根据文件大小排序 查看庐山真面貌的cat实例 :简单显示内容实例 :显示行号 -n实例 …

Python实现xml解析并输出到Excel上

1.编写xml文件 2.使用Python的ElementTree模块来解析XML import xml.etree.ElementTree as ET from openpyxl import Workbook # 解析XML函数 def parse_xml(xml_file):tree ET.parse(xml_file)root tree.getroot() --打开根节点data []for user in root.findall(Users/Us…

LeetCode 124 —— 二叉树中的最大路径和

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 二叉树的问题首先我们要想想是否能用递归来解决,本题也不例外,而递归的关键是找到子问题。 我们首先来看看一棵最简单的树,也就是示例 1。这样的一棵树总共有六条路径&#xf…

【三维修复、分割与编辑】InFusion、Bootstrap 3D、GaussianGrouping、GaussianEditor等(论文总结)

提示: 文章目录 前言一、InFusion:扩散模型助力,效率提高20倍!(2024)1. 摘要2. 算法3. 效果 二、2D Gaussian Splatting三、Bootstrap 3D:从扩散模型引导三维重建1.摘要2.相关工作3.方法1.Boostrapping by Diffusion 通过扩散模型…

文心一言 VS 讯飞星火 VS chatgpt (267)-- 算法导论20.2 2题

二、写出 PROTO-vEB-DELETE 的伪代码。通过扫描簇内的相关位,来更新相应的 summary 位。并且你实现的伪代码的最坏情况运行时间是多少?如果要写代码,请用go语言。 文心一言: 首先,让我们回顾一下vEB(Van …

项目管理-质量管理

目录 一、质量管理概述 1.1 GB/T16260.1-2006 定义 1.2 GB/T19000-ISO 9000(2000)系列标准定义 二、软件质量模型 2.1 软件全生命周期质量模型 2.1.1 内部和外部质量的质量模型 2.1.2 使用质量的质量模型 2.1.3 McCall 质量模型 2.1.4 质量特性度量 2.1.5 相关概念 三…

对话掌阅科技CTO孙凯:如何用生成式AI重新定义阅读体验

导读:生成式AI能对阅读做本质的改造吗? 读一本好书,犹如和一位智者对话。 对于很多热爱读书的人,这是一种令人憧憬的阅读体验。以往,这种对话只能在读者的头脑和思维中进行。 有没有可能,读者可以随时随地和…

使OpenCV可以读取中文路径图片的方法

一.问题复现 1.代码 #! /usr/bin/env python # -*- coding: utf-8 -*-# File: show_img.pyimport cv2# 读取图片 img cv2.imread("车牌素材/冀A.png")# 显示图片 cv2.imshow("img", img) cv2.waitKey(0)2.报错截图 3.报错内容 [ WARN:00.05…

[JAVASE] 类和对象综合应用 -- 图书管理系统

目录 零. 概览 一. 抽象出图书管理系统所涉及的对象 1.1 Book 1.2 User 1.3 Operation 二. 实现 User 包中的对象 2.1 User父类 2.2 NormalUser 对象 2.3 AdminUser 对象 2.4 小总结(1) 三. 实现Book包中的对象 3.1 Book 对象 3.2 BookList 对象 四. 实现 Operation…

大数据工具之HIVE-参数调优,调度乱码(二)

一、调度乱码 在利用HUE工具,搭建WORKFLOW流程的过程中,如果直接执行hivesql数据正常,不会出现乱码现象,如果利用WORKFLOW搭建的流程,进行数据的拉取,会出现数据中文乱码现象,这些乱码主要是由于select 中的硬编码中文导致出现的现象 具体现象如下: select case when …

【WEB前端2024】开源智体世界:乔布斯3D纪念馆-第26节-内嵌blender展厅

【WEB前端2024】开源智体世界:乔布斯3D纪念馆-第26节-内嵌blender展厅 使用dtns.network德塔世界(开源的智体世界引擎),策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界…

人工智能万卡 GPU 集群的硬件和网络架构

万卡 GPU 集群互联:硬件配置和网络设计 一、背景 自从 OpenAI 推出 ChatGPT 以来,LLM 迅速成为焦点关注的对象,并取得快速发展。众多企业纷纷投入 LLM 预训练,希望跟上这一波浪潮。然而,要训练一个 100B 规模的 LLM&a…

OpenWrt U盘安装使用 详细教程 x86/64平台 软路由实测 系列一

1 官方稳定 版:OpenWrt 23.05 OpenWrt Downloads #根据实际情况选择 PC支持uefi,选择版本:https://downloads.openwrt.org/releases/23.05.3/targets/x86/64/openwrt-23.05.3-x86-64-generic-ext4-combined-efi.img.gz 2 rufus 制作U盘启动 3 制作好的U盘,接入主…

经典链表题-链表回文结构

🎉🎉🎉欢迎莅临我的博客空间,我是池央,一个对C和数据结构怀有无限热忱的探索者。🙌 🌸🌸🌸这里是我分享C/C编程、数据结构应用的乐园✨ 🎈🎈&…

传输层——UDP

在学习计算机网络的过程中,我们知道OSI七层协议模型,但是在实际开发应 用中我们发现OSI七层协议模型并不适合实施,因为OSI上三层通常都是由开 发人员统一完成的,这三层之间在实现过程中没有一个明确的界限,所以我 们更…

Windows平台C#版RTSP转RTMP直播推送定制版

技术背景 前几年我们发布了C版的多路RTMP/RTSP转RTMP转发官方定制版。在秉承低延迟、灵活稳定、低资源占用的前提下,客户无需关注开发细节,只需图形化配置转发等各类参数,实现产品快速上线目的。 如监控类摄像机、NVR等,通过厂商…

关于堆排序

今天我们不刷力扣了,我们来复习(手撕)一下数据结构中的八大排序算法之一,堆排序 基本概念: 堆是一种特殊的树形数据结构,即完全二叉树。 堆分为大顶堆和小顶堆: 大顶堆:每个节点的值…