经典图像分割网络:Unet 支持libtorch部署推理【附代码】

简介: 笔记

深度学习中图像分割是属于像素级的分类,与目标检测和图像分类一样,经过卷积网络提前特征,只不过分割需要对这些特征在像素层面进行分类。


图像分割常应用于医学和无人驾驶领域,基于深度学习的图像分割以Unet为代表,也是很经典的网络,更是很多初学者接触的网络【也包括我】。这篇文章会大致讲一下Unet网络原理和代码,最终实现pytorch环境下python的推理和Libtorch C++推理(支持GPU和CPU)。


说明:


支持python与Libtorch C++推理


python版本支持支持对于单类别检测,C++暂不支持


python板支持视频检测,C++暂不支持(仅图像)


增加网络可视化工具


增加pth转onnx格式


增加pth转pt格式


环境


windows 10


pytorch:1.7.0(低版本应该也可以)


libtorch 1.7 Debug版


cuda 10.2


VS 2017


英伟达 1650 4G


Unet网络


先来看一下网络结构

10.png

可以看到上面的网络,因为形状是U型,因此称为Unet网络,Unet网络实际也属于encode-decode网络,网络的左边是encode部分,右边则是decode部分。


Unet分为三个部分:


主干特征提取网络(与VGG很像):可以获得5个初步的有效的特征层;

由卷积和最大池化构成


加强特征提取:通过对主干特征提取网络的5个有效特征层进行上采样(也可以进行反卷积),并且与右边网络特征进行特征融合,获得一个最终的,融合了所有特征的有效特征层;

预测部分:利用最终的特征层对每个特征点进行分类,相当于对每个像素点进行分类,而输出的通道数为自己的类别数+1(这个1是包含了背景分类);

最后得到这个特征层相当于是前面特征的特征浓缩,预测过程是对通道数的调整,把最后特征层的通道数调整成需要分类的个数,相当于对每个像素进行分类


有关Unet视频讲解可以看b站Up主:Bubbliiiing


数据集制作


本项目采用数据格式为VOC数据集格式,文件形式如下。


VOCdevkit/

|-- VOC2007

|   |-- ImageSets

|   |   `-- Segmentation

|   |-- JPEGImages

|   `-- SegmentationClass

`-- voc2unet.py


其中JPEGImages放原始图片.jpg,而SegmentationClass存放是标签文件,格式是png格式。比如像下面这样子。图中红色部分实际上有值的,比如我这个类别是对应1类,那么红色区域内像素则都为1

11.png

接下来讲怎么制作数据集。


图像分割数据集制作:用labelme工具制作,保存成json格式,再通过json格式进行转化成png格式


安装命令:


pip install labelme==3.16.7

首先将自己的数据集放在datasets文件下,目录形式如下:


datasets/

|-- JPEGImages

|-- SegmentationClass

`-- before


其中before文件夹是存放自己原始图像的 。


打开cmd,输入labelme【前提是已经安装好了】。界面如下,样子和labelimg很像对不对,但功能是有区别的。

12.png

然后通过右边的open dir打开图像路径,开始标注数据集,点击右下方的Create Polygons可以标注关键点(主要要闭环),你标注点越多当然就越好。然后会在你当前目录下生成一个Json文件。

13.png Json内容看下图,可以看到label就是我们自己标注的类,下面的points就是你标注时的关键点信息。


14.png

训练


然后进入json_to_dataset.py,修改classes,加入自己的类,注意!不要把_background_这个类删掉!!


运行以后,程序会将原始图copy到datasets/JPEGImags下,然后生成的png标签文件生成在datasets/SegmentationClass文件下。接下来就是这两个文件复制到VOCdevkit/VOC2007/中。


接下来是运行VOCdevkit/voc2unet.py,将会在ImageSets/Segmentation/下生成txt文件。


接下来就可以运行train.py进行训练了,这里需要主要更改  NUM_CLASSES 。


训练的权重会保存在logs下。


损失函数


训练过程中可以利用交叉熵作为损失函数(大多数有关分类的任务都会用这个损失函数),还可以加入dice_loss,可以更好的对样本进行平衡,而这个loss就是一个求FN、TP等这些东西[相信学目标检查测的同学很熟悉了吧],和它有关的则是召唤率与精确率了。该loss代码如下:

def Dice_loss(inputs, target, beta=1, smooth = 1e-5):
    # inputs是网络的output (batch_size, num_classes, input_shape[0], input_shape[1])
    # target是真实的png (batch_size, h,w, num_classes)
    n, c, h, w = inputs.size()
    nt, ht, wt, ct = target.size()
    if h != ht and w != wt:  # input和target是w h 是否相等
        inputs = F.interpolate(inputs, size=(ht, wt), mode="bilinear", align_corners=True)
    # temp_inputs shape(batch_size, w*h, c)
    temp_inputs = torch.softmax(inputs.transpose(1, 2).transpose(2, 3).contiguous().view(n, -1, c), -1)
    # temp_target (batch_size, w*h, c)
    temp_target = target.view(n, -1, ct)
    #--------------------------------------------#
    #   计算dice loss
    #   temp_target[...,:-1]去除背景类的真实值
    #   tp=Σ真实值*预测值
    #   fp = Σ预测值 - tp
    #   fn = Σ真实值 - tp
    #--------------------------------------------#
    tp = torch.sum(temp_target[..., :-1] * temp_inputs, axis=[0,1])
    fp = torch.sum(temp_inputs                       , axis=[0,1]) - tp
    fn = torch.sum(temp_target[...,:-1]              , axis=[0,1]) - tp
    # 3TP+smooth/(3TP+2FN+FP + smooth)
    score = ((1 + beta ** 2) * tp + smooth) / ((1 + beta ** 2) * tp + beta ** 2 * fn + fp + smooth)
    dice_loss = 1 - torch.mean(score)
    return dice_loss

FN:错误的负样本


TN:正确的负样本


TP:正确的正样本


FP:错误的正样本


精确度(P):在所有正样本中,被正确识别的正样本比例



P=TP/(TP+FP)


召回率(R):识别正确的正样本占正确的正样本和被识别成正样本的负样本比例



R=TP/(TP+FN)


F1:召回率和精确率的调和平均数



F1=2TP/(2TP+FN+FP)


预测

说明:本项目可以对所有类进行检测并分割,同时也支持单独某个类进行分割。


网络采用VGG16为backbone。在终端输入命令:


可以对图像进行预测:

python demo.py --predict --image


15.png

如果你想和原图进行叠加,在命令行输入:

python demo.py --predict --image --blend

image.png

视频预测:

python demo.py --predict --video --video_path 0

预测几个类时,用逗号','隔开:

python demo.py --predict --image --classes_list 15,7

image.png

参数说明:

model_path:权重路径

num_classes:类别数量(含背景),默认21

cuda:是否用GPU推理

predict 预测模式

image:图像预测

video:视频预测

video_path:视频路径,默认0

output:输出路径

fps:测试FPS

blend:分割图是否和原图叠加

classes_list:预测某些类,如果是多个类,用','隔开,例如:15,7


libtorch 推理


libtorch环境配置和一些遇到的问题可以参考我另一篇文章,这里不再说:


使用TorchScript和libtorch进行模型推理[附C++代码]_爱吃肉的鹏的博客-CSDN博客_libtorch 推理


进入tools文件,在pth2pt.py中修改权重路径,num_classes,还有输入大小(默认512).运行以后会保存.pt权重文件


将pt权重文件放在你想放的地方,我这里是放在了与我exe执行程序同级目录下。


打开通过VS 2017打开Libtorch_unet/Unet/Unet.sln,注意修改以下地方:(VS 配置libtorch看上面链接)


在main.cpp中最上面修改两个宏定义,一个是网络输入大小,一个是num_classes根据自己的需要修改。


COLOR Classes是我写的一个结构体,每个类对应的颜色,如果你自己的数据集小于21个类,那你不用修改,只需要记住哪个类对应哪个颜色即可。如果是大于21个类,需要自己在定义颜色。


在main.cpp torch::jit::load()修改自己的pt权重路径(如果你没和exe放一个目录中,建议填写绝对路径),当然,如果你希望通过传参的方式也可以,自己修改下即可。


argv[1]是图像路径(执行exe时可以传入)。


然后将项目重新生成,用cmd执行Unet.exe 接着输入图像路径,如下:


Unet.exe street.jpg


将会输出以下内容:

*****************************************
**        libtorch Unet图像分割项目    **
**          支持GPU和CPU推理           **
** 生成项目后执行exe并输入图像路径即可   **
**           作者:yinyipeng           **
**           联系方式:                **
**      微信:y24065939s               **
**      邮箱:15930920977@163.com      **
*****************************************
The model load success!
The cuda is available
cuda
put model into the cuda
The output shape is: [1, 21, 512, 512]
seq_img shape is [512, 512, 3]

可以看到C++推理结果和python是一样的,此刻就已经成功了。


image.png

不过我这里并没有计算libtorch的推理时间,但感觉好像是有点慢的,还需要进一步优化,而且应该是要用加速处理的。


一些注意事项


在libtorch推理中需要用到的一些代码,比如Mat转tensor,tensor转Mat等。


Mat转tensor


input是经过resize和转RGB的输入图像,转的shape(1,512,512,3)


torch::Tensor tensor_image = torch::from_blob(input.data, { 1,input.rows, input.cols,3 }, torch::kByte);

推理:


在实际验证中,如果在送入模型之前用tensor_image.to(device)即将张量放入cuda,在下面cuda推理中会报关于内存的错误,但在cpu下不会,感觉是libtorch的一个bug吧,但如果在forward函数中将tensor_image放入cuda就可以正常推理。这点需要注意。


output = module.forward({tensor_image.to(device)}).toTensor(); //The shape is [batch_size, num_classes, 512,512]

C++中张量的切片:


指的是对最后一个维度的第0维度进行操作

seg_img.index({ "...", 0 })

CUDA FLAOT32-->CUDA UINT8转CPU UINT8(GPU->CPU数据转换)


在cuda 32 float转cuda UINT 8再转cpu uint8时(因为最后需要CPU进行推理计算数据),也发现了一个问题,如果你在cuda上转uint8,然后用to(torch::kCPU)后,发现最终显示结果全黑,没有结果,但打印seg_img是有值的,后来打印了一下res这个矩阵,发现里面像素值全为0,且值为cpu float 32,但我要的是uint8,明明我前面转过了。即没有tensor数据没有拷贝到Mat中,解决方法是先将cuda放在cpu上,在转uint8,而不是在cuda上转uint8后再迁移到cpu。


//在放入CPU的时候,必须要转uint8型,否则后面无法将tensor拷贝至Mat
seg_img = seg_img.to(torch::kCPU).to(torch::kUInt8);

tensor转Mat


cv::Mat res(cv::Size(input_shape, input_shape), CV_8UC3,seg_img.data_ptr());


相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
2月前
|
人工智能 监控 数据可视化
如何破解AI推理延迟难题:构建敏捷多云算力网络
本文探讨了AI企业在突破算力瓶颈后,如何构建高效、稳定的网络架构以支撑AI产品化落地。文章分析了典型AI IT架构的四个层次——流量接入层、调度决策层、推理服务层和训练算力层,并深入解析了AI架构对网络提出的三大核心挑战:跨云互联、逻辑隔离与业务识别、网络可视化与QoS控制。最终提出了一站式网络解决方案,助力AI企业实现多云调度、业务融合承载与精细化流量管理,推动AI服务高效、稳定交付。
|
4月前
|
机器学习/深度学习 数据采集 算法
贝叶斯状态空间神经网络:融合概率推理和状态空间实现高精度预测和可解释性
本文将BSSNN扩展至反向推理任务,即预测X∣y,这种设计使得模型不仅能够预测结果,还能够探索特定结果对应的输入特征组合。在二元分类任务中,这种反向推理能力有助于识别导致正负类结果的关键因素,从而显著提升模型的可解释性和决策支持能力。
390 42
贝叶斯状态空间神经网络:融合概率推理和状态空间实现高精度预测和可解释性
|
3月前
|
机器学习/深度学习 并行计算 算法
【图像分割】基于神经气体网络的图像分割与量化(Matlab代码实现)
【图像分割】基于神经气体网络的图像分割与量化(Matlab代码实现)
|
7月前
|
人工智能 供应链 调度
|
6月前
|
传感器 算法 数据安全/隐私保护
基于GA遗传优化的三维空间WSN网络最优节点部署算法matlab仿真
本程序基于遗传算法(GA)优化三维空间无线传感网络(WSN)的节点部署,通过MATLAB2022A实现仿真。算法旨在以最少的节点实现最大覆盖度,综合考虑空间覆盖、连通性、能耗管理及成本控制等关键问题。核心思想包括染色体编码节点位置、适应度函数评估性能,并采用网格填充法近似计算覆盖率。该方法可显著提升WSN在三维空间中的部署效率与经济性,为实际应用提供有力支持。
|
Kubernetes Devops 持续交付
DevOps实践:使用Docker和Kubernetes实现持续集成和部署网络安全的守护盾:加密技术与安全意识的重要性
【8月更文挑战第27天】本文将引导读者理解并应用DevOps的核心理念,通过Docker和Kubernetes的实战案例,深入探讨如何在现代软件开发中实现自动化的持续集成和部署。文章不仅提供理论知识,还结合真实示例,旨在帮助开发者提升效率,优化工作流程。
|
7月前
|
存储 运维 监控
2025年4月深度评测:10款最值得部署的网络监控软件
真正卓越的运维不仅仅是对当前问题的解决,更在于对未来的预测和防范。 OpManager 的预测报表功能可以为用户提供有关未来存储需求增长方式的直观展示,帮助用户进行基于需求的容量规划,从而避免成本浪费。
353 0
|
8月前
|
人工智能 运维 监控
领先AI企业经验谈:探究AI分布式推理网络架构实践
当前,AI行业正处于快速发展的关键时期。继DeepSeek大放异彩之后,又一款备受瞩目的AI智能体产品Manus横空出世。Manus具备独立思考、规划和执行复杂任务的能力,其多智能体架构能够自主调用工具。在GAIA基准测试中,Manus的性能超越了OpenAI同层次的大模型,展现出卓越的技术实力。
|
供应链 监控 安全
网络安全中的零信任架构:从概念到部署
网络安全中的零信任架构:从概念到部署
967 75
|
9月前
|
传感器 算法 物联网
基于粒子群算法的网络最优节点部署优化matlab仿真
本项目基于粒子群优化(PSO)算法,实现WSN网络节点的最优部署,以最大化节点覆盖范围。使用MATLAB2022A进行开发与测试,展示了优化后的节点分布及其覆盖范围。核心代码通过定义目标函数和约束条件,利用PSO算法迭代搜索最佳节点位置,并绘制优化结果图。PSO算法灵感源于鸟群觅食行为,适用于连续和离散空间的优化问题,在通信网络、物联网等领域有广泛应用。该算法通过模拟粒子群体智慧,高效逼近最优解,提升网络性能。
367 16

热门文章

最新文章