200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 语义分割数据集VOC FCN网络结构详解

语义分割数据集VOC FCN网络结构详解

时间:2018-12-05 07:46:22

相关推荐

语义分割数据集VOC  FCN网络结构详解

1 什么是语义分割?

用一句话来说,语义分割的任务是使图像的每一个像素点回归到某一个标签上,而更为高级的有实例分割,实例分割除了将像素点的类别找出,还需要将像素点定位出不同实例。

2 FCN网络结构

再对比下图的VGG16网络结构

VGG16网络结构大体分为两部分,一是13个卷积层,二是3个全连接层,输入图像经过卷积和池化,下采样到512维的矩阵,最后拉平Flatten()成一维的向量,经过两次n-—>4096的全连接层,再进行最后一层的4096->1000的全连接层,最后softmax输出概率。这里为什么有两层或三层(convolution+relu)再池化,而不一步到位直接convolution+relu+池化到相应的尺寸,原因是这样做可以减少参数(可能会)和增加网络深度,且增加relu次数,提高非线性逼近能力,卷积为线性。

较少参数的说明:

c1->c2->c3 nums1= c1*c2*k12^2+c2*c3*k23^2

c1->c3nums2= c1*c3*k13^2

不同情况下,nums2有可能小于nums1

而FCN采用了VGG16的特征层features,即去除后面的全连接层, 全连接层会失去特征的空间信息,且需要大量的参数。 用kersize =1 的卷积替代全连接层 ,当然每次卷积后也需要激活。

self.conv1 = nn.Conv2d(512, 4096, 1)self.conv2 = nn.Conv2d(4096, 21, 1)

其中FCN-32s的实现最为简单,最后conv7以32倍的大小转置卷积回去,pytorch有自带的上采样语句

self.upsample32x = nn.Upsample(scale_factor=32, mode='bilinear', align_corners=False)

也等效

self.upsample_32x = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=64,stride=32, padding=16, bias=False)self.upsample_32x.weight.data = bilinear_kernel(num_classes, num_classes, 64)

而FCN-16s实现则是将conv7上采样,倍数为2,再将大小为输入的1/16的pool4卷积为同尺度的,与之连接,再上采样,其倍数为16.

pool4 = self.boclk1(x)#print(pool4.size())pool5 = self.boclk2(pool4)#print(pool5.size())s = self.conv1(pool5)s = self.relu(s)s = self.conv2(s)s = self.relu(s)#print(s.size())s = self.upsample2x(s)pool4 = self.scores(pool4)s = s+pool4s = self.upsample16x(s)

3训练过程和验证

训练损失采用交叉熵损失

criterion = nn.CrossEntropyLoss()output = fcn_model(bag)output = F.log_softmax(output, dim=1)loss = criterion(output, bag_msk)

训练Fcn-8s,epoch取5,主要是验证性,lr也不小,1e-2,训练结果如下图所示,比较粗糙,具体的验证结果量化可以用交并比:

4 数据的预处理:

voc数据的图片大小不一,具体可以用PIL.size 或者opencv,查看,这里选用的图片大小为320*480,原因是是32的倍数,且大于这大小的图片足够多,且不会大很多。

这里需要一个随机的裁剪,

import torchvision.transforms.functional as TF

#随机裁剪def rand_crop(self,input,label,crop_size):i, j, h, w = transforms.RandomCrop.get_params(input, output_size=crop_size)input = TF.crop(input, i, j, h, w)input = np.array(input)label = TF.crop(label, i, j, h, w)return input,label

对inputs的归一化处理

input_tfs = pose([transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])])input = input_tfs(input)

而转化为原数据则为

mean = torch.tensor([0.485, 0.456, 0.406]).reshape(3, 1, 1).to(device)std = torch.tensor([0.229, 0.224, 0.225]).reshape(3, 1, 1).to(device)inputs_nd = (inputs*std+mean).permute(0,2,3,1)*255

而对labels的标签化处理,读取RGB数据,转化为0-20的数

#标签图转为根据颜色转为单通道21分类def image2label(self,label):classes = ['background', 'aeroplane', 'bicycle', 'bird', 'boat','bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable','dog', 'horse', 'motorbike', 'person', 'potted plant','sheep', 'sofa', 'train', 'tv/monitor']# RGB color for each classcolormap = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], [0, 0, 128],[128, 0, 128], [0, 128, 128], [128, 128, 128], [64, 0, 0], [192, 0, 0],[64, 128, 0], [192, 128, 0], [64, 0, 128], [192, 0, 128],[64, 128, 128], [192, 128, 128], [0, 64, 0], [128, 64, 0],[0, 192, 0], [128, 192, 0], [0, 64, 128]]cm2lbl = np.zeros(256 ** 3) # 每个像素点有 0 ~ 255 的选择,RGB 三个通道#print(cm2lbl.shape)for i, cm in enumerate(colormap):cm2lbl[(cm[0] * 256 + cm[1]) * 256 + cm[2]] = i # 建立索引#plt.show(label)data = np.array(label, dtype='int32')idx = (data[:, :, 0] * 256 + data[:, :, 1]) * 256 + data[:, :, 2]#print(cm2lbl[idx].shape)#数组a以b为索引,返回b的形状,a[b][x,y] = a[b[x,y]]return np.array(cm2lbl[idx], dtype='int64') # 根据索引得到 label 矩阵

由预测转为图像可视化

def label2image(pred):# pred: [320,480]colormap = torch.tensor(colormap , device=device, dtype=int)x = pred.long()return (colormap[x, :]).data.cpu().numpy()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。