前言 在这一期中,我们先扼要温习一遍FCN网络,随后进入今天的重点——编码器-解码器架构。
本教程制止转载。同时,本教程来自常识星球【CV技能攻略】更多技能教程,可加入星球学习。
欢迎重视大众号CV技能攻略,专心于计算机视觉的技能总结、最新技能盯梢、经典论文解读、CV招聘信息。
CV各大方向专栏与各个部署结构最全教程收拾
【CV技能攻略】CV全栈辅导班、基础入门班、论文辅导班 全面上线!!
FCN结构
FCN根据传统的卷积神经网络 (CNN),但做了一些特定的改进,使其能够用于像素等级的语义切割使命。
或许我们还记得,在上一期中我们说到过FCN的网络结构:
网络结构
在蓝色箭头部分,实际上对图画进行了“卷积-BN-非线性”的集合操作,并在池化后让图画尺度变小;
在红色线部分,履行的是上采样操作(在pytorch官方完成中选用的是双线性插值);
在绿色矩形框部分,经过元素相加的办法对不同方位的特征图进行了交融;
浅显来说,我们先经过一系列的操作,对输入图画进行紧缩,再经过另一系列操作对图画进行解压。
于是,紧缩图画的那一系列结构我们就称之为编码器,而解压图画的另一系列结构我们称之为解码器。
网络结构
经过上图能够看到,最终我们能够得到1/32尺度的heatmap,1/16尺度的featuremap和1/8尺度的featuremap,将1/32尺度的heatmap进行上采样到原始尺度,这种模型叫做FCN-32s。这种简略粗暴的办法复原了conv5中的特征,但是其间一些细节是无法康复的,所以FCN-32s精度很差,不能够很好地复原图画原来的特征。
根据上述原因,所以自然而然的就想到将浅层网络提取的特征和深层特征相交融,这样或许能够更好地康复其间的细节信息。于是FCN把conv4中的特征对conv7进行2倍上采样之后的特征图进行交融,然后这时候特征图的尺度为原始图画的1/16,所以再上采样16倍就能够得到原始图画巨细的特征图,这种模型叫做FCN-16s。
为了进一步康复特征细节信息,就重复以上操作。于是乎就把pool3后的特征图对conv7上采样4倍后的特征图和对pool4进行上采样2倍的特征图进行交融,此时的特征图的巨细为原始图画的1/8。交融之后再上采样8倍,就能够得到原始图画巨细的特征图了,这种模型叫做FCN-8s。
代码完成
-
backbone部分
class VGG(nn.Module): def init(self, pretrained=True): super(VGG, self).init()
# conv1 1/2 self.conv1_1 = nn.Conv2d(3, 64, kernel_size=3, padding=1) self.relu1_1 = nn.ReLU(inplace=True) self.conv1_2 = nn.Conv2d(64, 64, kernel_size=3, padding=1) self.relu1_2 = nn.ReLU(inplace=True) self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # conv2 1/4 self.conv2_1 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.relu2_1 = nn.ReLU(inplace=True) self.conv2_2 = nn.Conv2d(128, 128, kernel_size=3, padding=1) self.relu2_2 = nn.ReLU(inplace=True) self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) # conv3 1/8 self.conv3_1 = nn.Conv2d(128, 256, kernel_size=3, padding=1) self.relu3_1 = nn.ReLU(inplace=True) self.conv3_2 = nn.Conv2d(256, 256, kernel_size=3, padding=1) self.relu3_2 = nn.ReLU(inplace=True) self.conv3_3 = nn.Conv2d(256, 256, kernel_size=3, padding=1) self.relu3_3 = nn.ReLU(inplace=True) self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2) # conv4 1/16 self.conv4_1 = nn.Conv2d(256, 512, kernel_size=3, padding=1) self.relu4_1 = nn.ReLU(inplace=True) self.conv4_2 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.relu4_2 = nn.ReLU(inplace=True) self.conv4_3 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.relu4_3 = nn.ReLU(inplace=True) self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2) # conv5 1/32 self.conv5_1 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.relu5_1 = nn.ReLU(inplace=True) self.conv5_2 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.relu5_2 = nn.ReLU(inplace=True) self.conv5_3 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.relu5_3 = nn.ReLU(inplace=True) self.pool5 = nn.MaxPool2d(kernel_size=2, stride=2) # load pretrained params from torchvision.models.vgg16(pretrained=True) if pretrained: pretrained_model = vgg16(pretrained=pretrained) pretrained_params = pretrained_model.state_dict() keys = list(pretrained_params.keys()) new_dict = {} for index, key in enumerate(self.state_dict().keys()): new_dict[key] = pretrained_params[keys[index]] self.load_state_dict(new_dict) def forward(self, x): x = self.relu1_1(self.conv1_1(x)) x = self.relu1_2(self.conv1_2(x)) x = self.pool1(x) pool1 = x x = self.relu2_1(self.conv2_1(x)) x = self.relu2_2(self.conv2_2(x)) x = self.pool2(x) pool2 = x x = self.relu3_1(self.conv3_1(x)) x = self.relu3_2(self.conv3_2(x)) x = self.relu3_3(self.conv3_3(x)) x = self.pool3(x) pool3 = x x = self.relu4_1(self.conv4_1(x)) x = self.relu4_2(self.conv4_2(x)) x = self.relu4_3(self.conv4_3(x)) x = self.pool4(x) pool4 = x x = self.relu5_1(self.conv5_1(x)) x = self.relu5_2(self.conv5_2(x)) x = self.relu5_3(self.conv5_3(x)) x = self.pool5(x) pool5 = x return pool1, pool2, pool3, pool4, pool5
-
FCN-8s部分
class FCNs(nn.Module): def init(self, num_classes, backbone=”vgg”): super(FCNs, self).init() self.num_classes = num_classes if backbone == “vgg”: self.features = VGG()
# deconv1 1/16 self.deconv1 = nn.ConvTranspose2d(512, 512, kernel_size=3, stride=2, padding=1, output_padding=1) self.bn1 = nn.BatchNorm2d(512) self.relu1 = nn.ReLU() # deconv1 1/8 self.deconv2 = nn.ConvTranspose2d(512, 256, kernel_size=3, stride=2, padding=1, output_padding=1) self.bn2 = nn.BatchNorm2d(256) self.relu2 = nn.ReLU() # deconv1 1/4 self.deconv3 = nn.ConvTranspose2d(256, 128, kernel_size=3, stride=2, padding=1, output_padding=1) self.bn3 = nn.BatchNorm2d(128) self.relu3 = nn.ReLU() # deconv1 1/2 self.deconv4 = nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, output_padding=1) self.bn4 = nn.BatchNorm2d(64) self.relu4 = nn.ReLU() # deconv1 1/1 self.deconv5 = nn.ConvTranspose2d(64, 32, kernel_size=3, stride=2, padding=1, output_padding=1) self.bn5 = nn.BatchNorm2d(32) self.relu5 = nn.ReLU() self.classifier = nn.Conv2d(32, num_classes, kernel_size=1) def forward(self, x): features = self.features(x) y = self.bn1(self.relu1(self.deconv1(features[4])) + features[3]) y = self.bn2(self.relu2(self.deconv2(y)) + features[2]) y = self.bn3(self.relu3(self.deconv3(y))) y = self.bn4(self.relu4(self.deconv4(y))) y = self.bn5(self.relu5(self.deconv5(y))) y = self.classifier(y) return y
FCN的编码器解码器结构
在 FCN 中,编码器是由多个卷积层构成的,用来提取输入图画的特征信息。因为卷积层会逐步减小图画的巨细,因此经过多次卷积之后,得到的特征图巨细会变小,也便是下采样。这个进程能够看做是对图画信息的紧缩和抽象,类似于将图画转换为一些更高层次的特征表明。
接下来,解码器担任将编码器输出的低分辨率特征图复原为原始图画巨细的高分辨率特征图。解码器经过一系列反卷积(也称为上采样)层进行图画的放大,逐步康复出原始图画中的更细节的信息。这个进程能够看做是将抽象的特征复原为原始图画的进程。
现在,你已经大约知道什么是__编码器解码器__结构了。
编码器-解码器
它是计算机视觉范畴中的一种根本网络结构,这种先紧缩,再解压的思维,在后续的许多结构中都会呈现,在语义切割范畴,这便是祖师爷般的存在~ 再提一句,一些很优异的网络(如 U-Net、SegNet 等),都是在在编码器-解码器结构的基础上进行了更细致的设计和改进得到的
优缺点
其实说到上面,中心内容已经讲完啦~ 这个结构的根本思维便是先紧缩,再解压,其他的内容就在其他网络中慢慢领会吧~ 下面来看一下十分十分简略的优缺点剖析:
优点:
能够提取高层次的特征信息:编码器经过卷积层等操作,能够有效地提取图画的高层次特征信息,这些信息对于图画分类、方针检测、语义切割等使命十分重要。
能够复原图画细节信息:解码器经过上采样、反卷积等操作,能够将编码器输出的低分辨率特征图复原为原始图画巨细的高分辨率特征图,从而康复出原始图画中的细节信息。
结构简略:编码器-解码器结构是一种相对简略的网络结构,易于了解和完成,而且具有较好的可解释性。
缺点:
因为多次卷积和池化操作,编码器-解码器结构会使得图画信息逐步丢掉,导致一些细节信息无法康复,例如边际和纹路等。
在解码器中运用反卷积和上采样等操作,容易引起信息的混叠和失真,导致图画质量下降。
编码器-解码器结构的练习需要许多的数据和计算资源,模型参数较多,练习进程较为困难。
编码器-解码器总结
编码器-解码器(encoder-decoder)是语义切割范畴中最重要的一种结构,它的中心思维便是先紧缩,再解压,后续说到的绝大部分网络选用的都是这种原始的结构。在此基础之上,我们能够改动上采样办法,在论文中常常叫做微调编码器;也能够改动上采样办法,在论文中常常叫做微调解码器。经过这两种办法,我们就能创造出许多许多的种样式的神经网络~
欢迎重视大众号CV技能攻略,专心于计算机视觉的技能总结、最新技能盯梢、经典论文解读、CV招聘信息。
计算机视觉入门1v3辅导班
【技能文档】《从零搭建pytorch模型教程》122页PDF下载
QQ沟通群:470899183。群内有大佬担任回答我们的日常学习、科研、代码问题。
其它文章
CUDA 教程(三)CUDA C 编程简介
方针盯梢(二)单、多方针盯梢的根本概念与常用数据集
【CV技能攻略】我们自己的CV全栈辅导班、基础入门班、论文辅导班 全面上线!!
即插即用模块 | RFAConv助力YOLOv8再涨2个点
CVPR 2023|21 篇数据集作业汇总(附打包下载链接)
CVPR 2023|两行代码高效缓解视觉Transformer过拟合,美图&国科大联合提出正则化办法DropKey
LargeKernel3D:在3D稀疏CNN中运用大卷积核
ViT-Adapter:用于密布预测使命的视觉 Transformer Adapter
CodeGeeX 130亿参数大模型的调优笔记:比FasterTransformer更快的解决方案
切割全部还不行,还要检测全部、生成全部,SAM二创开端了
CVPR 2023 深挖无标签数据价值!SOLIDER:用于以人为中心的视觉
SegGPT:在上下文中切割全部
上线一天,4k star | Facebook:Segment Anything
Efficient-HRNet | EfficientNet思维+HRNet技能会不会更强更快呢?
实践教程|GPU 利用率低常见原因剖析及优化
ICLR 2023 | SoftMatch: 完成半监督学习中伪标签的质量和数量的trade-off
方针检测创新:一种根据区域的半监督办法,部分标签即可(附原论文下载)
CNN的反击!InceptionNeXt: 当 Inception 遇上 ConvNeXt
神经网络的可解释性剖析:14种归因算法
无痛涨点:方针检测优化的实用Trick
详解PyTorch编译并调用自定义CUDA算子的三种办法
深度学习练习模型时,GPU显存不行怎么办?
deepInsight:一种将非图画数据转换图画的办法
ICLR2023|根据数据增广和常识蒸馏的单一样本练习算法
拯救脂肪肝第一步!自主诊断脂肪肝:3D医疗影像切割方案MedicalSeg
AI最全资料汇总 | 基础入门、技能前沿、工业应用、部署结构、实战教程学习
改动几行代码,PyTorch炼丹速度狂飙、模型优化时刻大减
AAAI 2023 | 轻量级语义切割新范式: Head-Free 的线性 Transformer 结构
计算机视觉入门1v3辅导班
计算机视觉沟通群
聊聊计算机视觉入门