使⽤PyTorch进⾏语义分割
本篇⽂章使⽤进⾏pytorch进⾏语义分割的实验。
1.什么是语义分割?二次根式化简
语义分割是⼀项图像分析任务,我们将图像中的每个像素分类为对应的类。 这类似于我们⼈类在默认情况下⼀直在做的事情。每当我们看到某些画⾯时,我们都会尝试“分割”图像的哪⼀部分属于哪个类/标签/类别。 从本质上讲,语义分割是我们可以在计算机中实现这⼀点的技术。 您可以在我们关于图像分割的帖⼦中阅读更多关于分割的内容。 这篇⽂章的重点是语义分割 ,所以,假设我们有下⾯的图像。
经过语义分割,会得到如下输出:
如您所见,图像中的每个像素都被分类为各⾃的类。例如,⼈是⼀个类,⾃⾏车是另⼀个类,第三个是背景。 简单说,这就是语义分割。
2.语义分割的应⽤
语义分割最常见的⽤例是:
2.1 ⾃动驾驶
在⾃主驾驶中,计算机驾驶汽车需要对前⾯的道路场景有很好的理解。分割出汽车、⾏⼈、车道和交通标志等物体是很重要的。
2.2 ⼈脸分割
⾯部分割⽤于将⾯部的每个部分分割成语义相似的区域-嘴唇、眼睛等。这在许多现实世界的应⽤程序中都是有⽤的。⼀个⾮常有趣的应⽤
程序可以是虚拟美颜。
2.3 室内物体分割
你能猜出这个在哪⾥使⽤吗?在AR(增强现实)和VR(虚拟现实)中。应⽤程序可以分割整个室内区域,以了解椅⼦、桌⼦、⼈、墙和其
嵊泗岛他类似物体的位置,从⽽可以⾼效地放置和操作虚拟物体。
2.4 ⼤地遥感
地球遥感是⼀种将卫星图像中的每个像素分类为⼀个类别的⽅法,以便我们可以跟踪每个区域的⼟地覆盖情况。因此,如果在某些地区发⽣了严重的森林砍伐,那么就可以采取适当的措施。在卫星图像上使⽤语义分割可以有更多的应⽤。
让我们看看如何使⽤PyTorch和Torchvision进⾏语义分割。
3 torchvision的语义分割
我们将研究两个基于深度学习的语义分割模型。全卷积⽹络(FCN)和DeepLabv3。这些模型已经在COCO Train 2017数据集的⼦集上进⾏了训练,该⼦集对应于PASCALVOC数据集。模型共⽀持20个类别。
3.1.输⼊和输出
在我们开始之前,让我们了解模型的输⼊和输出。 这些模型期望输⼊⼀个3通道图像(RGB),它使⽤Imagenet的均值和标准差归⼀化,即, 平均值=[0.485,0.456,0.406],标准差=[0.229,0.224,0.225] 。
输⼊维数为[Ni x Ci x Hi x Wi] ,其中,
Ni ->批次⼤⼩
Ci ->通道数(即3)
Hi ->图⽚的⾼度
Wi ->图像的宽度
⽽模型的输出维数为[No x Co x Ho x Wo] ,其中
No ->批次⼤⼩(与Ni相同)
Co->是数据集的类数!
Ho ->图像的⾼度(⼏乎在所有情况下都与Hi相同)
Wo ->图像的宽度(⼏乎在所有情况下都与Wi相同)
注:torchvision模型的输出是⼀个有序的字典,⽽不是⼀个torch.Tensor(张量)。 在推理(.val()模式)过程中,输出是⼀个有序的Dict,且只有⼀个键-值对,键为out,它的相应值具有[No x Co x Ho x Wo]的形状。
3.2.具有Resnet-101⾻⼲的FCN 全卷积⽹络了解英文
FCN是第⼀次成功的使⽤神经⽹络⽤于语义分割⼯作。让我们看看如何在Torchvision中使⽤该模型。
3.2.1 加载模型
ram容量
from torchvision import models
fcn = ation.fcn_resnet101(pretrained=True).eval()
很简单!我们有⼀个基于Resnet101的预先训练的FCN模型。如果模型尚未存在于缓存中,则pretrained=True标志将下载该模型。该.val ⽅法将以推理模式加载它。
3.2.2.加载图像
接下来,让我们加载⼀个图像!我们直接从URL下载⼀个鸟的图像并保存它。我们使⽤PIL加载图像。
在当前⽬录中,下载⼀张图⽚。
wget -nv uk/s3fs-public/thumbnails/image/2018/04/10/19/pinyon-jay-bird.jpg -O bird.png
加载显⽰图像
from PIL import Image
import matplotlib.pyplot as plt
import torch
img = Image.open('./bird.png')表格排名
plt.imshow(img); plt.show()
3.2.3.对图像进⾏预处理
为了使图像达到输⼊格式要求,以便使⽤模型进⾏推理,我们需要对其进⾏预处理并对其进⾏正则化! 因此,对于预处理步骤,我们进⾏以下操作。
将图像⼤⼩调整为(256x256)
将其转换为(224x224)
将其转换为张量-图像中的所有元素值都将被缩放,以便在[0,1]之间⽽不是原来的[0,255]范围内。
将其正则化,使⽤Imagenet数据 的均值=[0.485,0.456,0.406],标准差=[0.229,0.224,0.225]海盗王子
最后,我们对图像进⾏增加维度,使它从[C x H x W]变成[1x C x H x W]。这是必需的,因为模型需要按批处理图像。
# Apply the transformations needed
ansforms as T
trf = T.Compo([T.Resize(256),
T.CenterCrop(224),
T.ToTensor(),
T.Normalize(mean = [0.485, 0.456, 0.406],
std = [0.229, 0.224, 0.225])])
inp = trf(img).unsqueeze(0)养胃的汤
让我们看看上⾯的代码单元是做什么的。 torchvision有许多有⽤的函数。其中之⼀是⽤于预处理图像的Transforms。T.Compo是⼀个函数,它接受⼀个列表,其中每个元素都是transforms 类型,它返回⼀个对象,我们可以通过这个对象传递⼀批图像,所有所需的转换都将应⽤于图像。
让我们来看看应⽤于图像上的转换:
T.Resize(256):将图像尺⼨调整为256×256
不稂不莠T.CenterCrop(224):从图像的中⼼抠图,⼤⼩为224x224
T.ToTensor():将图像转换为张量,并将值缩放到[0,1]范围
T.Normalize(mean, std):⽤给定的均值和标准差对图像进⾏正则化。
3.2.
4.正向传递通过⽹络
现在我们已经对图像进⾏了所有的预处理,让我们通过模型并得到OUT键。 正如我们前⾯提到的,模型的输出是⼀个有序的Dict,所以我们需要从其中取出out键的value来获得模型的输出。
# Pass the input through the net
out = fcn(inp)['out']
print (out.shape)
输出为:
torch.Size([1, 21, 224, 224])
所以,out是模型的最终输出。正如我们所看到的,它的形状是[1 x 21 x H x W],正如前⾯所讨论的。因为,模型是在21个类上训练的,输出有21个通道!(包括背景类) 现在我们需要做的是,使这21
个通道输出到⼀个2D图像或⼀个1通道图像,其中该图像的每个像素对应于⼀个类! 因此,2D图像(形状[HxW])的每个像素将与相应的类标签对应,对于该2D图像中的每个(x,y)像素将对应于表⽰类的0-20之间的数字。 我们如何从这个[1 x 21 x H x W]的列表到达那⾥?我们为每个像素位置取⼀个最⼤索引,该索引表⽰类的下标,看到这⾥是否似曾相识,对了,之前的⽂章讲到,多分类的输出是⼀个列表,存有每个类的置信度,这⾥每个像素点的21个通道对应着每个类的置信度。
import numpy as np
om = torch.argmax(out.squeeze(), dim=0).detach().cpu().numpy()
print (om.shape)
(224, 224)