Python实例分割 YOLOv5 segment使用教程(完善中)
Posted 此彼之间白夜幻想
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python实例分割 YOLOv5 segment使用教程(完善中)相关的知识,希望对你有一定的参考价值。
目录
本文是我在使用YOLOv5时,做的一些过程记录,按照步骤走应该能够跟我获得相同的结果,初次写这种类型的文章,排版之类的可能不太好看,内容也不够充分,之后混慢慢修改补充。
本文内容包含代码的直接使用方式,与在自定义数据集上的使用方式,目前未使用过其他公开数据集进行试用。
一、直接试用方式
1、准备工作
配置conda,虚拟环境与torch,这一部分有很多教程,这里就不写了。
代码下载:GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
环境准备:pip install -r requirements.txt。
或者按照官方教程文件:
!git clone https://github.com/ultralytics/yolov5 # clone
%cd yolov5
%pip install -qr requirements.txt # install
import torch
import utils
display = utils.notebook_init() # checks
2、代码测试
(1)、模型训练(可以跳过)
打开segment/train.py,直接运行,会自动下载预训练模型参数yolov5s-seg.pt与数据集coco128-seg,模型参数会下载到yolov5目录下,数据集会下载到yolov5父目录下。训练结果会保存在runs/train-seg/exp中。
或者自行下载模型参数:https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt
(2)、模型预测
打开segment/predict.py,直接运行,会将/home/w/下载/yolov5-master/data/images中的两张图像进行分割预测(没有使用上面的训练参数),分割结果会保存在runs/predict-seg/exp。
分割结果如下:
二、制作自己的数据集
1、格式
数据集文件夹格式:
其中images文件夹下放的是原始图像,labels文件夹下放的是满足YOLOv5要求的txt标签文件。
将原始数据按照文件夹格式复制可参考:
https://blog.csdn.net/a1004550653/article/details/128329796
txt文件格式:
第一个数字为类别,后面每两个数字代表一个点对于整张图像的相对位置。每一行代表图像中的一个mask。
2、labelme制作标签
制作自己的数据集的话,打标签是无可避免的,用labelme就足以满足基本需求。这一部分的教程也很多,也就先不写了,有机会再加。
3、json转txt
通过labelme可以得到json格式的mask标签。按照下面的代码可以将其修改为需要的格式。
https://blog.csdn.net/a1004550653/article/details/128320398
4、修改数据集参数
复制coco123_seg.yaml,修改名称,例如mydataset.yaml。
修改内部参数:
path为数据集目录,train为其子目录相对路径,val可以与train相同,test不用设置。names为不同的分类与名称,改成自己的就好。
三、用YOLOv5跑自己的数据集
1、train.py参数修改
weigeht是预训练模型,可以使用自己的,也可以下载官方的。
data是数据集格式,改成刚才创建的yaml名称。
hyp是数据增强,可以按照需求在文件内自行增改。
epochs为训练轮数,训练中会自动保存最好与最后一次的模型参数。
batch--size为一次训练的图片个数,配置够的话可以增加。
imgsz等为训练时的图像重置大小。
基本上只用动上面几个参数就够了,如果还有别的需求,可以看help里面的描述,自行修改。
例如下面还有个optimizer,优化器,默认sgd。
当参数带有action='store_true',那么默认不会运行,运行时需要用终端加上--xxx(例如Python train.py --nosave)。
2、predict.py参数修改
weight修改为训练得到的自己的权重,默认位置在run/train-seg/exp/weight下。
source为需要预测的图像文件夹。
data设置与train相同。
imgsz建议使用默认的640,数值增大,结果可能会更精细,但是检测框可能会不够大。
conf-thres为置信阈值,只有检测框的概率高于阈值时,才会被留下。
iou-thres为交并比阈值,在进行NMS(非极大值抑制)时,超过阈值的检测框会被删除。
max-det为一张图中检测框存在的最大数量,因为个人需要,我会设置为1。
save-txt会将分割结果按照YOLOv5的格式保存为txt文件,可以通过txt文件再转换为需要的mask。
save-crop会将检测框内部图像截图保存。
如果不加别的处理,原始图像经过predict.py后,会得到一张实例分割的图像。
3、txt2mask
将预测得到的txt转换为需要的mask图像。
https://blog.csdn.net/a1004550653/article/details/128313599
四、遇到过的报错与解决方式
五、原理(部分)
1、图像标签转换
在yolov5-seg中,准备的txt文件中包含的是类别与seg点位,在实际训练的过程中,seg点位会被转换为检测用的box信息,即xywh。具体的转换代码如下:
def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0):
# Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] normalized where xy1=top-left, xy2=bottom-right
if clip:
clip_boxes(x, (h - eps, w - eps)) # warning: inplace clip
y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
y[:, 0] = ((x[:, 0] + x[:, 2]) / 2) / w # x center
y[:, 1] = ((x[:, 1] + x[:, 3]) / 2) / h # y center
y[:, 2] = (x[:, 2] - x[:, 0]) / w # width
y[:, 3] = (x[:, 3] - x[:, 1]) / h # height
return y
def segments2boxes(segments):
# Convert segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh)
boxes = []
for s in segments:
x, y = s.T # segment xy
boxes.append([x.min(), y.min(), x.max(), y.max()]) # cls, xyxy
return xyxy2xywh(np.array(boxes)) # cls, xywh
2、分割原理
在yolov5s-seg模型下,图像重置大小设置为640,将图片与标签输入模型后得到pred与proto。
其中pred形状为[1, 22680, 38],经过nms后得到检测框信息,每个检测框形状为[1, 38],向量中0-3为检测框位置,4为检测框的置信度,5为分类,6-37为mask协方差系数。
proto的形状为[1, 32, 160, 144],(160,144)是输入图像下采样两次后的大小。
mask的求取方法为,用pred中的mask的协方差系数,与proto做矩阵乘法,得到mask的具体输出,大小为[1, 160, 144],再经过crop_mask,只保留检测框范围内的数据,最后经过上采样,大小为[1, 640, 576]。
def crop_mask(masks, boxes):
"""
"Crop" predicted masks by zeroing out everything not in the predicted bbox.
Vectorized by Chong (thanks Chong).
Args:
- masks should be a size [h, w, n] tensor of masks
- boxes should be a size [n, 4] tensor of bbox coords in relative point form
"""
n, h, w = masks.shape
x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n)
r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1)
c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None] # cols shape(h,1,1)
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
def process_mask(protos, masks_in, bboxes, shape, upsample=False):
"""
Crop before upsample.
proto_out: [mask_dim, mask_h, mask_w]
out_masks: [n, mask_dim], n is number of masks after nms
bboxes: [n, 4], n is number of masks after nms
shape:input_image_size, (h, w)
return: h, w, n
"""
c, mh, mw = protos.shape # CHW
ih, iw = shape
masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) # CHW
downsampled_bboxes = bboxes.clone()
downsampled_bboxes[:, 0] *= mw / iw
downsampled_bboxes[:, 2] *= mw / iw
downsampled_bboxes[:, 3] *= mh / ih
downsampled_bboxes[:, 1] *= mh / ih
masks = crop_mask(masks, downsampled_bboxes) # CHW
if upsample:
masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW
return masks.gt_(0.5)
for i, det in enumerate(pred):
masks = process_mask(proto[i], det[:, 6:], det[:, :4], im.shape[2:], upsample=True) # HWC
图像分割:Semantic/Instance/Panoramic Segmentation
一. 背景介绍
语义分割(Semantic Segmentation):对一张图片上的所有像素点进行分类,同一物体的不同实例不需要单独分割出来。
实例分割(Instance Segmentation):目标检测(比b-box更精确到边缘)和语义分割(标出同类不同个体)的结合。
全景分割(Panoramic Segmentation):语义分割和实例分割的结合,背景也要检测和分割。
图像分割是图像理解的重要基石,在自动驾驶、无人机、工业质检等应用中都有着举足轻重的地位。缺陷检测论文现在好多都是借助语义分割方法做的迁移应用到实际的工业现场等,比如国外知名的VIDI软件、国内一些检测软件。
二. 语义分割
1. 【UNet】
结构:
Unet主要针对生物医学图像分割。继承FCN的思想。整体结构就是先编码(下采样),对图像的低级局域像素值进行归类与分析,从而获得高阶语义信息; 再解码(上采样),收集这些语义信息,并将同一物体对应到相应的像素点上,回归到跟原始图像一样大小的像素点的分类。
encoder的基本单元是:两个valid卷积层(图像size会减小)接一个max pooling(2x2)下采样(1/2);
decoder的基本单元是:[up-conv(2x2)+skip connection]接两个valid卷积层。
U-Net的skip connection不同于FCN的对应像素求和,是对channel的concat(拼接)过程。Unet上采样部分可以用上采样或转置卷积,这里详细解释下up-conv转置卷积。
实际在计算机中,并不是逐像素滑动计算,效率太低。而是将卷积核转换成等效的矩阵,通过输入向量和卷积核矩阵相乘获得输出向量。如图,input:4x4,Kernel:3x3,Padding/Stride:0,output:2x2,卷积核要在输入的不同位置卷积4次,通过补零将卷积核分别置于一个4x4矩阵的四个角落,这样输入可以直接和这四个4x4的矩阵进行卷积,取代了滑窗操作。将输入展开为[16,1]向量X,输出矩阵记作Y([4,1]),四个4x4卷积核分别展开并拼接成卷积矩阵C([16,4])。普通的卷积运算可表示为矩阵运算:XT * C = YT。
我们将一个1x16的行向量乘以16x4的矩阵,得到了1x4的行向量。反过来,在需要输入一个小的特征,输出更大尺寸的特征时,将一个1x4的向量乘以一个4x16的矩阵就能得到一个1x16的行向量,这就是转置卷积的思想。根据普通卷积,公式改写为:YT * CT = XT。
普通卷积和转置卷积这两个操作不可逆,同一个卷积核在转置卷积操作之后不能恢复原始数值,只恢复形状。相同的形状就足够了,在训练中我们可以学习卷积核对应的权值来还原图像。
关键策略:
encoder的基本单元是:2-3个same卷积层(图像size不变,BN对训练图像的分布归一化,加速学习)接一个max pooling(2x2)下采样;
decoder的基本单元是:upsampling接2-3个same卷积层,卷积为上采样放大的图像丰富信息,使池化过程丢失的信息被重建。
SegNet在pooling上有个创新,引入了index功能。这里详细解释下。
如上图,每次pooling,都会保存通过max选出的权值在2x2 filter中的相对位置,6在粉色2x2 filter中的位置为(1,1)(index从0开始),黄色的3的index为(0,0)。同时,从网络结构图可以看到绿色的pooling与红色的upsampling通过pooling indices相连,表示pooling后的indices输出到对应的upsampling层。upsampling中先对输入的特征图放大两倍,然后把输入特征图的数据根据pooling indices放入,如下图所示。
2x2的输入变成4x4的图,除了被记住位置的pooling indices,其他位置的权值为0,因为数据已经被pooling走了。因此,SegNet使用卷积来填充缺失的内容。
(2).分类策略。
在网络框架中,SegNet最后一个卷积层会输出所有的类别(包括其他类),网络最后加上一个softmax层,由于是端到端,所以softmax需要求出每一个像素在所有类别最大的概率,作为该像素的label,最终完成图像像素级别的分类。
encoder: 原DeepLabv3作为encoder,ASPP有四个不同的rate,额外一个全局平均池化;
decoder: 先把encoder的结果上采样4倍,然后与resnet中下采样前的特征(先1x1卷积降通道数)concat,再进行3x3的卷积,最后上采样4倍输出结果。
关键策略:
(1).深度可分离卷积(Depthwise separable convolution)。
encoder
的主干网络
Xception
中引入的深度可分离卷积:
depthwise_separable_convolution = depthwise_convolution(先每个通道上独自进行空间卷积)
+ pointwise_convolution(再用1x1卷积核组合前面dep_conv得到的特征),在保持网络性能的同时,大幅减少参数量。
(2).空洞卷积(dilated convolution)。
又叫膨胀卷积,是通过增加一个超参数dilation rate(kernel的间隔数量),在标准的卷积图里注入空洞来增加感受野,有效避免了upsampling和pooling设计的缺陷:参数不可学习、内部数据结构及空间层级化信息丢失、小物体信息无法重建。
但是,Gridding Effect(kernel不连续,不是所有的pixel都用来计算)会使膨胀卷积损失信息的连续性,另外,单凭大dilation rate获得的信息可能对小物体分割没效果。通向标准化设计,Hybrid Dilated Convolution(HDC)因此被引入。HDC有三个特征:叠加卷积的dilation rate不能有大于1的公约数;将dilation rate设计成锯齿状结构,如[1, 2, 5, 1, 2, 5]循环结构;第2层的最大dilation rate M2 <= kernel size(k),至少可以用dilation rate 1(标准卷积)来覆盖掉所有洞。
(3).ASPP(astrous spatial pyramid pooling)。
ASPP通过不同的rate构建不同感受野的卷积核,捕获多尺度信息,并联(串联)不同膨胀率的空洞卷积,来获取更多上下文信息。
(4).encoder-decoder结构。
把ASPP模块和encoder-decoder结合在一起,encoder-decoder结构可以更好的地恢复物体的边缘信息。
以上是关于Python实例分割 YOLOv5 segment使用教程(完善中)的主要内容,如果未能解决你的问题,请参考以下文章
深度学习yolov5 tag7.0 实例分割 从0到1的体会,从模型训练,到量化完成
[软件工具][原创]将labelme数据集一键转换成yolov5和yolov7实例分割数据集工具使用教程
图像分割:Semantic/Instance/Panoramic Segmentation
弱监督实例分割 Box-supervised Instance Segmentation with Level Set Evolution 论文笔记