精华内容
下载资源
问答
  • FCN图像语义分割代码

    2019-04-14 16:51:25
    图像语义分割 FCN方法,使用tensorflow库,解压使用即可
  • 用FCM算法实现了图像分割,效果较好,可以更改聚类数目
  • FCM实现图像分割,fcn图像分割,matlab源码.rar
  • FCM实现图像分割,fcn图像分割,matlab源码.zip
  • 使用深度学习图像分割进行背景替换 该项目演示了如何使用完全卷积网络来进行图像分割,以进行有效的背景置换 样本 描述 该任务利用预先训练的FCN8s模型(在pascal-voc上训练)来创建仅针对人类存在的分割蒙版。 得到...
  • 用于训练的合成图像/遮罩 首先克隆存储库并cd到项目目录。 import matplotlib . pyplot as plt import numpy as np import helper import simulation # Generate some random images input_images , target_masks =...
  • FCN网络是深度学习图像分割领域的奠基之作,有着极大的意义.今天就来简单介绍一下FCN全卷积网络. 这篇论文的标题为"Fully Convolutional Networks for Semantic Segmentation",也就是全卷积...

    FCN网络是深度学习图像分割领域的奠基之作,有着极大的意义.今天就来简单介绍一下FCN全卷积网络.

    这篇论文的标题为"Fully Convolutional Networks for Semantic Segmentation",也就是全卷积网络应用于语义分割.

    传统的分类卷积神经网络,如AlexNet,VGG等都是输入一幅图像,输出图像所属类别的概率,因此为对整幅图像的类别的预测.而本文中的FCN全卷积网络则适用于图像语义分割,即输入一幅图像,输出仍然为一幅图像,只是分割出原图像中需要的类别.这样就不能再使用传统的分类模型了.下面将具体介绍一下FCN全卷积网络.

    1.语义分割和密集预测

    密集预测是一种基于密集像素的图像处理任务,具体的有语义分割,边界预测,图像复原,图像定位等任务.这些任务与图像分类任务最明显的区别就在于,他们需要对整幅图像中的每一个像素点进行操作,因此是一种密集预测.

    FCN模型要解决的问题是图像语义分割.它是一种端到端,像素到像素的预测任务,要求输入原始图像,输出图像中对应类别的分割图.

    2.FCN模型介绍

    FCN网络沿用了VGG分类网络的前几层,并将最后的三层全连接层替换为相应的卷积层,并在网络的最后添加了上采样层(upsampling layer),将图像复原到原先的尺寸.网络的简单结构示意图如图所示:
    FCN网络结构示意图
    上图仅仅是FCN-32s的示意图,另外的FCN-16s和FCN-8s中包含有跳跃结构,后面将具体解释.

    全卷积网络

    正如这篇论文标题所说的,FCN模型的最大的特点就在于使用了全卷积网络.在传统的分类任务中,无论网络前段使用什么样的结构,最后都会接着两层或者三层全连接层,即将卷积得到的三维特征图拉直为一维向量,通过全连接层进行概率预测.在FCN模型中,完全抛弃了全连接层,并且全部用卷积层替代,从头到尾的进行卷积操作.最后将会得到一个三维的特征图,这个特征图的每一个channel的特征图代表一个类别的分数,以此进行预测.具体结构如下:
    在这里插入图片描述
    全卷积神经网络的主要优点在于可以输入任意大小的图像.

    在一个卷积神经网络中,可以很明显的看到卷积层是与输入图像的大小没有关系的,即无论图像多大,都可以进行卷积操作,只是卷积层输出的特征图大小不同.在卷积神经网络中,真正限制输入图像大小的是最后的全连接层神经元数,因为全连接层单元数必须与最后一层卷积的输出特征图相匹配(否则会造成全连接层权值参数个数不一致).使用全卷积网络使用卷积层替换全连接层,这样就没有全连接层单元数的限制,因此可以输入任意大小的图像(至少要大于224X224).
    当输入不同大小的图像时全卷积网络将会产生不同大小的输出特征图,例如输入224X224的图像,则输出特征图为1X1X1000,输入512X512的图像,则输出特征图为16X16X1000.
    另外,全卷积网络输出三维特征图,保留了原始图像中的坐标信息,这是全连接层所不具备的.
    在这里插入图片描述

    上采样方法

    论文中提出了上采样方法,即整个FCN网络模型的最后一层上采样层(FCN-32s).在通过整个全卷积网络之后,原始图像被提炼为 m ∗ n ∗ 1000 m*n*1000 mn1000的特征图,里面包含着整幅图像的高级特征,并且能够预测图像类别.最后还需要添加一个上采样层,将提炼得到的特征图反卷积为原始图像大小,并显示分割图像.

    上采样可以看做是卷积和池化的逆操作.因子为 f f f的上采样可以看做是对原始图像的步长为 1 / f 1/f 1/f的卷积,当 f f f为整数的时候,也可以看做是对输出图像的步长为 f f f反卷积操作.

    反卷积(deconvolution)有很多种方法,插值法,转置卷积法等都是经典的反卷积方法,本文中采用的是双线性插值.双线性插值的基本思想就是根据与像素点相邻的四个像素点进行x,y两个方向的线性插值,从而得到该像素点的预测值.

    跳跃结构

    该论文中的另一个创新点在于使用了跳跃结构.如下图所示:
    FCN模型跳跃结构
    未使用跳跃结构的模型为FCN-32s,它直接将最后一层池化的特征图进行反卷积得到分割图像.原始图像经过FCN模型中的5次池化,图像大小压缩为原来的 1 / 32 1/32 1/32,因此FCN-32s模型中的最后一层直接对它进行了因子 f f f为32的上采样操作,由于上采样倍数过大,输出图像完全无法体现出原始图像的细节,是的结果非常差.在FCN-16s和FCN-8s中使用了跳跃结构如上图所示,FCN-16s模型将第四次池化后的特征图与第五次池化后的特征图结合,既保留了图像的高阶特征,又不会损失过多的图像细节,得到的分割结果明显好于FCN-32s.FCN-8s模型与FCN-16s模型类似.

    以FCN-16s模型为例,具体的融合过程为:首先对最后一个池化后的特征图进行因子为2的上采样操作,转化为2X2的图像,然后再与第四次池化后的2X2的特征图相叠加,最后对叠加后的结果进行因子为16的上采样操作.

    shift and stitch

    要从粗糙的原始图像上采样得到密集预测,文中提出了shift and stitch方法,但是最后的FCN模型中似乎没有使用该方法。shift and stitch的主要思想是对原始图像进行多层次平移池化,即原始图像产生多套池化特征图,最后上采样的时候可以根据多个池化特征图精准的复原图像。具体操作是,设降采样因子为f,把输入图像向右平移x个像素,向下平移y个像素,x,y分别从0~f,产生 f 2 f^2 f2个版本的池化特征图,理论上这些特征图的总和包含原始图像的全部信息,没有因为池化而损失信息。把这 f 2 f^2 f2个版本的特征图连接起来(stitch),就是上采样过程。

    我认为作者在最终的模型中并没有使用该方法,可能是由于每次池化都需要将原图像分裂为 f 2 f^2 f2池化特征图,经过多次池化过程,实际上神经网络会变得非常大,计算效率不高。经过实验可以学习的跨层融合的上采样过程效果更好效率都更加高效。

    patchwise training

    实际上我也完全没看懂patchwise training是什么意思,可能在以前的语义分割中用的较多,具体的一个patch训练与一张图片训练有什么区别,我还有待研究。。。

    ** 3.训练过程**

    和其他分割网络模型相同,FCN模型损失函数为像素级的交叉熵损失函数也采用了动量的随机梯度下降优化算法。FCN的前半部分网络是基于VGG的卷积层,因此直接引用VGG网络的权值参数作为FCN的预训练参数。然后再进行微调。

    展开全文
  • 全卷积网络FCN进行图像分割

    千次阅读 2018-07-12 10:59:26
    原文地址:全卷积网络FCN进行图像分割背景 CNN能够对图片进行分类,可是怎么样才能识别图片中特定部分的物体,在2015年之前还是一个世界难题。神经网络大神Jonathan Long发表了《Fully Convolutional Networks for ...

    原文地址:全卷积网络FCN进行图像分割

    背景

        CNN能够对图片进行分类,可是怎么样才能识别图片中特定部分的物体,在2015年之前还是一个世界难题。神经网络大神Jonathan Long发表了《Fully Convolutional Networks for Semantic Segmentation》在图像语义分割挖了一个坑,于是无穷无尽的人往坑里面跳。

    全卷积网络 Fully Convolutional Networks

    CNN 与 FCN

    通常CNN网络在卷积层之后会接上若干个全连接层, 将卷积层产生的特征图(feature map)映射成一个固定长度的特征向量。以AlexNet为代表的经典CNN结构适合于图像级的分类和回归任务,因为它们最后都期望得到整个输入图像的一个数值描述(概率),比如AlexNet的ImageNet模型输出一个1000维的向量表示输入图像属于每一类的概率(softmax归一化)。

    栗子:下图中的猫, 输入AlexNet, 得到一个长为1000的输出向量, 表示输入图像属于每一类的概率, 其中在“tabby cat”这一类统计概率最高。

    FCN对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。

    最后逐个像素计算softmax分类的损失, 相当于每一个像素对应一个训练样本。下图是Longjon用于语义分割所采用的全卷积网络(FCN)的结构示意图:

    简单的来说,FCN与CNN的区域在把于CNN最后的全连接层换成卷积层,输出的是一张已经Label好的图片。

    其实,CNN的强大之处在于它的多层结构能自动学习特征,并且可以学习到多个层次的特征:较浅的卷积层感知域较小,学习到一些局部区域的特征;较深的卷积层具有较大的感知域,能够学习到更加抽象一些的特征。这些抽象特征对物体的大小、位置和方向等敏感性更低,从而有助于识别性能的提高。下图CNN分类网络的示意图:

    这些抽象的特征对分类很有帮助,可以很好地判断出一幅图像中包含什么类别的物体,但是因为丢失了一些物体的细节,不能很好地给出物体的具体轮廓、指出每个像素具体属于哪个物体,因此做到精确的分割就很有难度。

    传统的基于CNN的分割方法:为了对一个像素分类,使用该像素周围的一个图像块作为CNN的输入用于训练和预测。这种方法有几个缺点:一是存储开销很大。例如对每个像素使用的图像块的大小为15x15,然后不断滑动窗口,每次滑动的窗口给CNN进行判别分类,因此则所需的存储空间根据滑动窗口的次数和大小急剧上升。二是计算效率低下。相邻的像素块基本上是重复的,针对每个像素块逐个计算卷积,这种计算也有很大程度上的重复。三是像素块大小的限制了感知区域的大小。通常像素块的大小比整幅图像的大小小很多,只能提取一些局部的特征,从而导致分类的性能受到限制。

    而全卷积网络(FCN)则是从抽象的特征中恢复出每个像素所属的类别。即从图像级别的分类进一步延伸到像素级别的分类。

    全连接层 -> 成卷积层

    全连接层和卷积层之间唯一的不同就是卷积层中的神经元只与输入数据中的一个局部区域连接,并且在卷积列中的神经元共享参数。然而在两类层中,神经元都是计算点积,所以它们的函数形式是一样的。因此,将此两者相互转化是可能的:

    对于任一个卷积层,都存在一个能实现和它一样的前向传播函数的全连接层。权重矩阵是一个巨大的矩阵,除了某些特定块,其余部分都是零。而在其中大部分块中,元素都是相等的。 相反,任何全连接层都可以被转化为卷积层。比如,一个 K=4096 的全连接层,输入数据体的尺寸是 7∗7∗512,这个全连接层可以被等效地看做一个 F=7,P=0,S=1,K=4096 的卷积层。换句话说,就是将滤波器的尺寸设置为和输入数据体的尺寸一致了。因为只有一个单独的深度列覆盖并滑过输入数据体,所以输出将变成 1∗1∗4096,这个结果就和使用初始的那个全连接层一样了。

    全连接层转化为卷积层:在两种变换中,将全连接层转化为卷积层在实际运用中更加有用。假设一个卷积神经网络的输入是 224x224x3 的图像,一系列的卷积层和下采样层将图像数据变为尺寸为 7x7x512 的激活数据体。AlexNet使用了两个尺寸为4096的全连接层,最后一个有1000个神经元的全连接层用于计算分类评分。我们可以将这3个全连接层中的任意一个转化为卷积层:

    针对第一个连接区域是[7x7x512]的全连接层,令其滤波器尺寸为F=7,这样输出数据体就为[1x1x4096]了。 针对第二个全连接层,令其滤波器尺寸为F=1,这样输出数据体为[1x1x4096]。 对最后一个全连接层也做类似的,令其F=1,最终输出为[1x1x1000]

    实际操作中,每次这样的变换都需要把全连接层的权重W重塑成卷积层的滤波器。那么这样的转化有什么作用呢?它在下面的情况下可以更高效:让卷积网络在一张更大的输入图片上滑动,得到多个输出,这样的转化可以让我们在单个向前传播的过程中完成上述的操作。

    举个栗子:如果我们想让224×224尺寸的浮窗,以步长为32在384×384的图片上滑动,把每个经停的位置都带入卷积网络,最后得到6×6个位置的类别得分。上述的把全连接层转换成卷积层的做法会更简便。如果224×224的输入图片经过卷积层和下采样层之后得到了[7x7x512]的数组,那么,384×384的大图片直接经过同样的卷积层和下采样层之后会得到[12x12x512]的数组。然后再经过上面由3个全连接层转化得到的3个卷积层,最终得到[6x6x1000]的输出((12 – 7)/1 + 1 = 6)。这个结果正是浮窗在原图经停的6×6个位置的得分!

    面对384×384的图像,让(含全连接层)的初始卷积神经网络以32像素的步长独立对图像中的224×224块进行多次评价,其效果和使用把全连接层变换为卷积层后的卷积神经网络进行一次前向传播是一样的。
    Evaluating the original ConvNet (with FC layers) independently across 224x224 crops of the 384x384 image in strides of 32 pixels gives an identical result to forwarding the converted ConvNet one time.

    如下图所示,FCN将传统CNN中的全连接层转化成卷积层,对应CNN网络FCN把最后三层全连接层转换成为三层卷积层。在传统的CNN结构中,前5层是卷积层,第6层和第7层分别是一个长度为4096的一维向量,第8层是长度为1000的一维向量,分别对应1000个不同类别的概率。FCN将这3层表示为卷积层,卷积核的大小 (通道数,宽,高) 分别为 (4096,1,1)、(4096,1,1)、(1000,1,1)。看上去数字上并没有什么差别,但是卷积跟全连接是不一样的概念和计算过程,使用的是之前CNN已经训练好的权值和偏置,但是不一样的在于权值和偏置是有自己的范围,属于自己的一个卷积核。因此FCN网络中所有的层都是卷积层,故称为全卷积网络。

    下图是一个全卷积层,与上图不一样的是图像对应的大小下标,CNN中输入的图像大小是同意固定resize成 227x227 大小的图像,第一层pooling后为55x55,第二层pooling后图像大小为27x27,第五层pooling后的图像大小为13*13。而FCN输入的图像是H*W大小,第一层pooling后变为原图大小的1/4,第二层变为原图大小的1/8,第五层变为原图大小的1/16,第八层变为原图大小的1/32(勘误:其实真正代码当中第一层是1/2,以此类推)。

    经过多次卷积和pooling以后,得到的图像越来越小,分辨率越来越低。其中图像到 H/32∗W/32 的时候图片是最小的一层时,所产生图叫做heatmap热图,热图就是我们最重要的高维特征图,得到高维特征的heatmap之后就是最重要的一步也是最后的一步对原图像进行upsampling,把图像进行放大、放大、放大,到原图像的大小。

    最后的输出是1000张heatmap经过upsampling变为原图大小的图片,为了对每个像素进行分类预测label成最后已经进行语义分割的图像,这里有一个小trick,就是最后通过逐个像素地求其在1000张图像该像素位置的最大数值描述(概率)作为该像素的分类。因此产生了一张已经分类好的图片,如下图右侧有狗狗和猫猫的图。

    upsampling

    相较于使用被转化前的原始卷积神经网络对所有36个位置进行迭代计算,使用转化后的卷积神经网络进行一次前向传播计算要高效得多,因为36次计算都在共享计算资源。这一技巧在实践中经常使用,一次来获得更好的结果。比如,通常将一张图像尺寸变得更大,然后使用变换后的卷积神经网络来对空间上很多不同位置进行评价得到分类评分,然后在求这些分值的平均值。

    最后,如果我们想用步长小于32的浮窗怎么办?用多次的向前传播就可以解决。比如我们想用步长为16的浮窗。那么先使用原图在转化后的卷积网络执行向前传播,然后分别沿宽度,沿高度,最后同时沿宽度和高度,把原始图片分别平移16个像素,然后把这些平移之后的图分别带入卷积网络。

    如下图所示,当图片在网络中经过处理后变成越小的图片,其特征也越明显,就像图像中颜色所示,当然啦,最后一层的图片不再是一个1个像素的图片,而是原图像 H/32xW/32 大小的图,这里为了简化而画成一个像素而已。

    如下图所示,对原图像进行卷积conv1、pool1后原图像缩小为1/2;之后对图像进行第二次conv2、pool2后图像缩小为1/4;接着继续对图像进行第三次卷积操作conv3、pool3缩小为原图像的1/8,此时保留pool3的featureMap;接着继续对图像进行第四次卷积操作conv4、pool4,缩小为原图像的1/16,保留pool4的featureMap;最后对图像进行第五次卷积操作conv5、pool5,缩小为原图像的1/32,然后把原来CNN操作中的全连接变成卷积操作conv6、conv7,图像的featureMap数量改变但是图像大小依然为原图的1/32,此时图像不再叫featureMap而是叫heatMap。

    现在我们有1/32尺寸的heatMap,1/16尺寸的featureMap和1/8尺寸的featureMap,1/32尺寸的heatMap进行upsampling操作之后,因为这样的操作还原的图片仅仅是conv5中的卷积核中的特征,限于精度问题不能够很好地还原图像当中的特征,因此在这里向前迭代。把conv4中的卷积核对上一次upsampling之后的图进行反卷积补充细节(相当于一个差值过程),最后把conv3中的卷积核对刚才upsampling之后的图像进行再次反卷积补充细节,最后就完成了整个图像的还原。

    缺点

    在这里我们要注意的是FCN的缺点:
    1、是得到的结果还是不够精细。进行8倍上采样虽然比32倍的效果好了很多,但是上采样的结果还是比较模糊和平滑,对图像中的细节不敏感。

    2、是对各个像素进行分类,没有充分考虑像素与像素之间的关系。忽略了在通常的基于像素分类的分割方法中使用的空间规整(spatial regularization)步骤,缺乏空间一致性。

    实践

    输入的图片是:

    现在可以直接来点代码吗?
    # import package
    import numpy as np
    from PIL import Image
    import caffe

    # 初始化地址
    caffe_root = 'fcn.berkeleyvision.org-master/voc-fcn8s/'
    model_def = caffe_root + 'deploy.prototxt' # 模型文件
    model_weights = caffe_root + 'fcn8s-heavy-pascal.caffemodel' #模型权重值
    test_image = 'images/2007_000129.jpg' #测试图片

    # load image, switch to BGR, subtract mean, and make dims C x H x W for Caffe
    im = Image.open(test_image)
    in_ = np.array(im, dtype=np.float32)
    in_ = in_[:,:,::-1] # change RGB image to BGR image
    in_ -= np.array((104.00698793,116.66876762,122.67891434))
    in_ = in_.transpose((2,0,1)) # Reshape the image from (500, 334, 3) to (3, 500, 334)

    net = caffe.Net(model_def, model_weights, caffe.TEST) #导入模型
    net.blobs['data'].reshape(1, *in_.shape)
    net.blobs['data'].data[...] = in_ #读入图像
    net.forward() #图片进入前馈卷积神经网络
    out = net.blobs['score'].data[0].argmax(axis=0) #最后得到的图片

    print net.blobs['score'].data[0].shape #(21, 500, 334)
    print net.blobs['score'].data[0].argmax(axis=0)

    好了,已经用fcn模型训练网一张图片了,接着就是要看看图片到底是怎么样的楽
    import matplotlib.pyplot as plt
    # display plots in this notebook
    %matplotlib inline

    # set display defaults

    print out.shape
    plt.imshow(out)

    输出是:

    现在做图片分割的都是基于FCN的升级版、FCN超级升级版,FCN改版、FCN超级改版。。。个人觉得最难的、也是个人正在学习的是从如何研究自己的样本,什么样的样本集才能提高最后结果的精度和召回率;有了样本然后怎么给CNN训练,训练后如何把CNN->FCN,然后到FCN能够对新的数据进行分割。整套流程能够自动化下来就更加perfect了。

    展开全文
  • 图像语义分割 -- FCN

    2021-01-20 03:44:54
    一:图像语义分割 最简答理解图像语义分割呢就是看下面的图片例子: 像素级别的分类: 假如像素有五个类别,那么最后输出的结果在长度和宽度上是一样的,只不过通道数就是类别个数了。拆解开各个通道就是如下所示:...

    一:图像语义分割
    最简答理解图像语义分割呢就是看下面的图片例子:
    像素级别的分类:
    在这里插入图片描述

    假如像素有五个类别,那么最后输出的结果在长度和宽度上是一样的,只不过通道数就是类别个数了。拆解开各个通道就是如下所示:
    在这里插入图片描述

    合并后就是各个像素的类别信息了,一般情况下会不同的颜色来表示各个类别,这样我们就能更加清晰看出来哪些像素是什么类别了,这也是一个监督学习的例子。
    在这里插入图片描述

    二:FCN
    由于自己太懒了,关于FCN的概念和介绍请自己自行百度哈。推荐下面链接
    https://zhuanlan.zhihu.com/p/31428783
    https://www.pianshen.com/article/1189524224/
    太多重复的我就不写了,请直接看上面的链接咯,会的就直接跳过忽略,总体来说,
    CNN是用来做图像分类的,是图像级别的,较浅的卷积层感知域较小,学习到一些局部区域的特征,较深的卷积层具有较大的感知域,能够学习到更加抽象一些的特征。
    但是由于CNN在进行convolution和pooling过程中丢失了图像细节,即feature map size逐渐变小,所以不能很好地指出物体的具体轮廓、指出每个像素具体属于哪个物体,无法做到精确的分割。
    FCN是把CNN最后的FC层全部改成了卷积层,这样就会得到2维的输出,能对应到原始图像每一个像素的类别,后接softmax获得每个像素点的分类信息,从而解决了分割问题。
    在这里插入图片描述

    三:FCN的结构
    如下所示:
    在这里插入图片描述

    简单描述下其结构:
    1:image经过多个conv和加一个max pooling变为pool1 feature,宽高变为1/2。
    2:pool1 feature再经过多个conv家加一个max pooling变为pool2 feature,宽高变为1/4。
    3:pool2 feature再经过多个conv加一个max pooling变为pool3 feature,宽高变为1/8。
    4:pool3 feature再经过多个conv加一个max pooling变为pool4 feature,宽高变为1/16。
    5:pool4 feature再经过多个conv加一个max pooling变为pool5 feature,宽高变为1/32。

    这里是得到了五个特征feature,这个是不是很熟悉啊?
    我们才学过的那个VGG不就是这么个结构么?除了我们上篇文章学习的VGG16,还有其他VGG结构,我们等下都会涉及到。

    但是这里只是特征提取阶段,我们下一步得进行特征融合等操作,这个才是FCN的重头啊。
    1:对于FCN-32,直接将最后的输出通过反卷积扩大32倍。
    2:对于FCN-16,先把pool5反卷积扩大2倍,再和pool相加,最后通过反卷积扩大16倍。
    3:对于FCN-8,先把pool5反卷积扩大2倍,再和pool相加,得到的值扩大2倍,再和pool3相加,最后通过反卷积扩大8倍。

    四:代码实现

    复用了VGG的结构。
    VGG有VGG11,VGG13,VGG16和VGG19,后两者是最常用的结构,他们的特点就是
    前面特征提取层都是五层结构,最后公用两个FC层,在FCN中会把这里卷积改成卷积。
    输入时数据是[batch, 3, W, H]。五层分别会得到[batch, 64, W, H],[batch, 128, W, H],[batch, 256, W, H],[batch, 512, W, H],[batch, 512, W, H]。
    至于VGG11,VGG13,VGG16和VGG19的结构呢,可以代码查看下

    import torch
    import torchvision
    
    # Press the green button in the gutter to run the script.
    if __name__ == '__main__':
        net = torchvision.models.vgg11(pretrained=True)   # 从预训练模型加载VGG11网络参数
        print(net)
    
        net = torchvision.models.vgg13(pretrained=True)   # 从预训练模型加载VGG13网络参数
        print(net)
    
        net = torchvision.models.vgg16(pretrained=True)   # 从预训练模型加载VGG16网络参数
        print(net)
    
        net = torchvision.models.vgg19(pretrained=True)   # 从预训练模型加载VGG19网络参数
        print(net)
    

    为了减少数据量的计算,在反卷积的之前会先进行降维的操作,详细见代码。

    完整代码如下:

    from torch import nn
    import torch
    import torchvision
    
    # ranges 是用于方便获取和记录每个池化层得到的特征图
    # 各个vgg原始定义的特征输出的层数
    ranges = {
        'vgg11': ((0, 3), (3, 6), (6, 11), (11, 16), (16, 21)),
        'vgg13': ((0, 5), (5, 10), (10, 15), (15, 20), (20, 25)),
        'vgg16': ((0, 5), (5, 10), (10, 17), (17, 24), (24, 31)),
        'vgg19': ((0, 5), (5, 10), (10, 19), (19, 28), (28, 37))
    }
    
    
    class VGGTest(nn.Module):
        def __init__(self, vgg='vgg16'):  # num_classes,此处为 二分类值为2
            super(VGGTest, self).__init__()
            net = {}
            if vgg == 'vgg11':
                net = torchvision.models.vgg11(pretrained=True)  # 从预训练模型加载VGG11网络参数
            elif vgg == 'vgg13':
                net = torchvision.models.vgg13(pretrained=True)  # 从预训练模型加载VGG13网络参数
            elif vgg == 'vgg16':
                net = torchvision.models.vgg16(pretrained=True)  # 从预训练模型加载VGG16网络参数
            elif vgg == 'vgg19':
                net = torchvision.models.vgg19(pretrained=True)  # 从预训练模型加载VGG19网络参数
    
            self.pool1 = net.features[ranges[vgg][0][0]: ranges[vgg][0][1]]  # [batch, 64, W, H]
            self.pool2 = net.features[ranges[vgg][1][0]: ranges[vgg][1][1]]  # [batch, 128,W, H]
            self.pool3 = net.features[ranges[vgg][2][0]: ranges[vgg][2][1]]  # [batch, 256,W, H]
            self.pool4 = net.features[ranges[vgg][3][0]: ranges[vgg][3][1]]  # [batch, 512,W, H]
            self.pool5 = net.features[ranges[vgg][4][0]: ranges[vgg][4][1]]  # [batch, 512,W, H]
    
        def forward(self, x):
            pool1_features = self.pool1(x)  # 1/2
            pool2_features = self.pool2(pool1_features)  # 1/4
            pool3_features = self.pool3(pool2_features)  # 1/8
            pool4_features = self.pool4(pool3_features)  # 1/16
            pool5_features = self.pool5(pool4_features)  # 1/32
    
            return pool1_features, pool2_features, pool3_features, pool4_features, pool5_features
    
    
    class FCN32s(nn.Module):
        def __init__(self, vgg='vgg16', num_classes=21):  # num_classes,最后的通道数。也是像素分类的个数。
            super(FCN32s, self).__init__()
    
            # 掐年5个提取特征层
            self.net_features = VGGTest(vgg)
    
            # 最后俩个那个FC层,被改造成两个Conv层
            self.FC_Layers = nn.Sequential(
                # fc6
                nn.Conv2d(512, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d(),
    
                # fc7
                nn.Conv2d(4096, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d()
            )
    
            # 输出层之前,先降维一下。
            self.score_pool5 = nn.Conv2d(4096, num_classes, 1)
            # 最后把降维后的数据进行反卷积(上采样)
            self.final_x32 = nn.ConvTranspose2d(num_classes, num_classes, 32, stride=32, bias=False)
    
        def forward(self, x):
            # 得到5个特征
            features = self.net_features(x)
    
            # 最后一个特征图还要进行FC操作
            last_features = self.FC_Layers(features[-1])
    
            # 先降行通道降维,减少运算量,再上采样(反卷积法)
            pool5 = self.score_pool5(last_features)
    
            out = self.final_x32(pool5)
            return out
    
    
    class FCN16s(nn.Module):
        def __init__(self, vgg='vgg16', num_classes=21):  # num_classes,此处为 二分类值为2
            super(FCN16s, self).__init__()
    
            # 掐年5个提取特征层
            self.net_features = VGGTest(vgg)
    
            # 最后俩个那个FC层,被改造成两个Conv层
            self.FC_Layers = nn.Sequential(
                # fc6
                nn.Conv2d(512, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d(),
    
                # fc7
                nn.Conv2d(4096, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d()
            )
    
            # 输出层之前,先降维一下。
            self.score_pool5 = nn.Conv2d(4096, num_classes, 1)
            self.score_pool4 = nn.Conv2d(512, num_classes, 1)
            # 最后把降维后的数据进行反卷积(上采样)
            self.upscore_pool5_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.final_x16 = nn.ConvTranspose2d(num_classes, num_classes, 16, stride=16, bias=False)
    
        def forward(self, x):
            # 得到5个特征
            features = self.net_features(x)
    
            # 最后一个特征图还要进行FC操作
            last_features = self.FC_Layers(features[-1])
    
            # 先降行通道降维,减少运算量,再上采样(反卷积法)
            pool5 = self.score_pool5(last_features)
            pool4 = self.score_pool4(features[-2])
    
            out = pool4 + self.upscore_pool5_x2(pool5)
    
            out = self.final_x16(out)
            return out
    
    
    class FCN8s(nn.Module):
        def __init__(self, vgg='vgg16', num_classes=21):  # num_classes,此处为 二分类值为2
            super(FCN8s, self).__init__()
    
            # 掐年5个提取特征层
            self.net_features = VGGTest(vgg)
    
            # 最后俩个那个FC层,被改造成两个Conv层
            self.FC_Layers = nn.Sequential(
                # fc6
                nn.Conv2d(512, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d(),
    
                # fc7
                nn.Conv2d(4096, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d()
            )
    
            # 输出层之前,先降维一下。
            self.score_pool5 = nn.Conv2d(4096, num_classes, 1)
            self.score_pool4 = nn.Conv2d(512, num_classes, 1)
            self.score_pool3 = nn.Conv2d(256, num_classes, 1)
            # 最后把降维后的数据进行反卷积(上采样)
            self.upscore_pool5_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.upscore_pool4_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.final_x8 = nn.ConvTranspose2d(num_classes, num_classes, 8, stride=8, bias=False)
    
        def forward(self, x):
            # 得到5个特征
            features = self.net_features(x)
    
            # 最后一个特征图还要进行FC操作
            last_features = self.FC_Layers(features[-1])
    
            # 先行通道降维,减少运算量,再上采样(反卷积法)
            pool5 = self.score_pool5(last_features)
            pool4 = self.score_pool4(features[-2])
            pool3 = self.score_pool3(features[-3])
    
            out = pool4 + self.upscore_pool5_x2(pool5)
            out = pool3 + self.upscore_pool4_x2(out)
    
            out = self.final_x8(out)
            return out
    
    
    class FCN4s(nn.Module):
        def __init__(self, vgg='vgg16', num_classes=21):  # num_classes,此处为 二分类值为2
            super(FCN4s, self).__init__()
    
            # 掐年5个提取特征层
            self.net_features = VGGTest(vgg)
    
            # 最后俩个那个FC层,被改造成两个Conv层
            self.FC_Layers = nn.Sequential(
                # fc6
                nn.Conv2d(512, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d(),
    
                # fc7
                nn.Conv2d(4096, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d()
            )
    
            # 输出层之前,先降维一下。
            self.score_pool5 = nn.Conv2d(4096, num_classes, 1)
            self.score_pool4 = nn.Conv2d(512, num_classes, 1)
            self.score_pool3 = nn.Conv2d(256, num_classes, 1)
            self.score_pool2 = nn.Conv2d(128, num_classes, 1)
            # 最后把降维后的数据进行反卷积(上采样)
            self.upscore_pool5_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.upscore_pool4_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.upscore_pool3_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.final_x4 = nn.ConvTranspose2d(num_classes, num_classes, 4, stride=4, bias=False)
    
        def forward(self, x):
            # 得到5个特征
            features = self.net_features(x)
    
            # 最后一个特征图还要进行FC操作
            last_features = self.FC_Layers(features[-1])
    
            # 先行通道降维,减少运算量,再上采样(反卷积法)
            pool5 = self.score_pool5(last_features)
            pool4 = self.score_pool4(features[-2])
            pool3 = self.score_pool3(features[-3])
            pool2 = self.score_pool2(features[-4])
    
            out = pool4 + self.upscore_pool5_x2(pool5)
            out = pool3 + self.upscore_pool4_x2(out)
            out = pool2 + self.upscore_pool3_x2(out)
    
            out = self.final_x4(out)
            return out
    
    
    class FCN2s(nn.Module):
        def __init__(self, vgg='vgg16', num_classes=21):  # num_classes,此处为 二分类值为2
            super(FCN2s, self).__init__()
    
            # 掐年5个提取特征层
            self.net_features = VGGTest(vgg)
    
            # 最后俩个那个FC层,被改造成两个Conv层
            self.FC_Layers = nn.Sequential(
                # fc6
                nn.Conv2d(512, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d(),
    
                # fc7
                nn.Conv2d(4096, 4096, 1),
                nn.ReLU(inplace=True),
                nn.Dropout2d()
            )
    
            # 输出层之前,先降维一下。
            self.score_pool5 = nn.Conv2d(4096, num_classes, 1)
            self.score_pool4 = nn.Conv2d(512, num_classes, 1)
            self.score_pool3 = nn.Conv2d(256, num_classes, 1)
            self.score_pool2 = nn.Conv2d(128, num_classes, 1)
            self.score_pool1 = nn.Conv2d(64, num_classes, 1)
            # 最后把降维后的数据进行反卷积(上采样)
            self.upscore_pool5_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.upscore_pool4_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.upscore_pool3_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.upscore_pool2_x2 = nn.Sequential(
                nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False),
                nn.ReLU(inplace=True)
            )
            self.final_x2 = nn.ConvTranspose2d(num_classes, num_classes, 2, stride=2, bias=False)
    
        def forward(self, x):
            # 得到5个特征
            features = self.net_features(x)
    
            # 最后一个特征图还要进行FC操作
            last_features = self.FC_Layers(features[-1])
    
            # 先进行通道降维,减少运算量,再上采样(反卷积法)
            pool5 = self.score_pool5(last_features)
            pool4 = self.score_pool4(features[-2])
            pool3 = self.score_pool3(features[-3])
            pool2 = self.score_pool2(features[-4])
            pool1 = self.score_pool1(features[-5])
    
            out = pool4 + self.upscore_pool5_x2(pool5)
            out = pool3 + self.upscore_pool4_x2(out)
            out = pool2 + self.upscore_pool3_x2(out)
            out = pool1 + self.upscore_pool2_x2(out)
    
            out = self.final_x2(out)
            return out
    
    
    if __name__ == '__main__':
        # model = VGGTest()
        x = torch.rand(64, 3, 224, 224)
        print(x.shape)
        num_classes = 21  # 假设最后像素的类别是num_classes,那么通道数就是num_classes
    
        # model = FCN32s()
        # model = FCN16s()
        # model = FCN8s()
        # model = FCN4s()
        model = FCN2s(num_classes=num_classes)
        y = model(x)
        print(y.shape)
    
    展开全文
  • 图像分割网络FCN原理详解

    千次阅读 2019-01-01 18:40:01
    卷积神经网络从图像分类到到对象检测、实例分割、到图像语义分割、是卷积特征提取从粗糙输出到精炼输出的不断升级,基于卷积神经网络的全卷积分割网络FCN是像素级别的图像语义分割网络,相比以前传统的图像分割方法...

    一、全卷积网络(FCN)

    卷积神经网络从图像分类到到对象检测实例分割、到图像语义分割、是卷积特征提取从粗糙输出到精炼输出的不断升级,基于卷积神经网络的全卷积分割网络FCN是像素级别的图像语义分割网络,相比以前传统的图像分割方法,基于卷积神经网络的分割更加的精准,适应性更强。

    为了了解全卷积网络,我们必须他与普通CNN网络的区别:

    1.1 CNN网络

    通常CNN网络在卷积层之后会接上若干个全连接层, 将卷积层产生的特征图(feature map)映射成一个固定长度的特征向量。以AlexNet为代表的经典CNN结构适合于图像级的分类和回归任务,因为它们最后都期望得到整个输入图像的一个数值描述(概率),比如AlexNet的ImageNet模型输出一个1000维的向量表示输入图像属于每一类的概率(softmax归一化)。

    • 举例:下图中的猫, 输入AlexNet, 得到一个长为1000的输出向量, 表示输入图像属于每一类的概率, 其中在“tabby cat”这一类统计概率最高(如下图)。
      在这里插入图片描述
    1.2 全卷积网络(FCN)

    FCN对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类(如上图)。

    简而言之:FCN与CNN的区域在把于CNN最后的全连接层换成卷积层,输出的是一张已经Label好的图片。

    二、网络实现

    FCN的卷积网络部分可以采用VGG、GoogleNet、AlexNet等作为前置基础网络,在这些的预训练基础上进行迁移学习与finetuning,对反卷积的结果跟对应的正向feature map进行叠加输出(这样做的目的是得到更加准确的像素级别分割),根据上采样的倍数不一样分为FCN-8S、FCN-16S、FCN-32S,图示如下:

    • 详情:
      对原图像进行卷积 conv1、pool1后原图像缩小为1/2;
      之后对图像进行第二次 conv2、pool2后图像缩小为1/4;
      继续对图像进行第三次卷积操作conv3、pool3缩小为原图像的1/8,此时保留pool3的featureMap;
      继续对图像进行第四次卷积操作conv4、pool4,缩小为原图像的1/16,保留pool4的featureMap;
      最后对图像进行第五次卷积操作conv5、pool5,缩小为原图像的1/32,
      然后把原来CNN操作中的全连接变成卷积操作conv6、conv7,图像的featureMap数量改变但是图像大小依然为原图的1/32,此时图像不再叫featureMap而是叫heatMap。

    • 实例
      现在我们有1/32尺寸的heatMap,1/16尺寸的featureMap和1/8尺寸的featureMap,1/32尺寸的heatMap进行upsampling操作之后,因为这样的操作还原的图片仅仅是conv5中的卷积核中的特征,限于精度问题不能够很好地还原图像当中的特征,因此在这里向前迭代。把conv4中的卷积核对上一次upsampling之后的图进行反卷积补充细节(相当于一个差值过程),最后把conv3中的卷积核对刚才upsampling之后的图像进行再次反卷积补充细节,最后就完成了整个图像的还原。(关于上采样不懂的自行百度)
      在这里插入图片描述
      在这里插入图片描述
      github:https://github.com/muyang0320/tf-fcn
      在这里我们要注意的是FCN的缺点:

    • 是得到的结果还是不够精细。进行8倍上采样虽然比32倍的效果好了很多,但是上采样的结果还是比较模糊和平滑,对图像中的细节不敏感。

    • 是对各个像素进行分类,没有充分考虑像素与像素之间的关系。忽略了在通常的基于像素分类的分割方法中使用的空间规整(spatial regularization)步骤,缺乏空间一致性。

    展开全文
  • 语义图像分割的目标在于标记图片中每一个像素,并将每一个像素与其表示的类别对应起来。因为会预测图像中的每一个像素,所以一般将这样的任务称为密集预测。(相对地,实例分割模型是另一种不同的模型,该模型可以...
  • 5 FCN模型图像分割 5.1 FCN模型模型与数据介绍 FCN模型 支持20个分割标签  使用模型实现图像分割 5.2 模型文件  二进制模型 - fcn8s-heavy-pascal.caffemodel 官网下载  网络描述 - fcn8s-heavy-pascal....
  • 最近在用pytorch写FCN时,将损失函数换成了CrossEntropyLoss,出现的问题是在第一个反向传播后,loss一下变成了0,之后再怎么训练loss都是0不再变化。而最初的loss看起来是一个正常的浮点数,很显然网络不可能经过一...
  • 图像分割算法FCN论文解读

    千次阅读 2019-08-19 15:34:03
    论文名称:Fully Convolutional Networks for Semantic Segmentation ... 代码地址:...语义分割是指对图像进行像素级别的分类,即标注出图像中每个像素所属的类别。 这篇论文是语义...
  • 最近一直在尝试将FCN网络运用到指纹图像分割上,并将其与公司原有的指纹采集工具融合,改进原有工具在对非按压、带水区域的标记分割。学习一段时间了,有一些小小的心得,在此记录一下。  FCN网络的Demo是使用...
  • 全卷积网络(FCN)与图像分割

    万次阅读 多人点赞 2016-05-14 02:00:07
    与传统用CNN进行图像分割的方法相比,FCN有两大明显的优点:一是可以接受任意大小的输入图像,而不用要求所有的训练图像和测试图像具有同样的尺寸。二是更加高效,因为避免了由于使用像素块而带来的重复存储和计算...
  • 全卷积神经网络FCN模型Unet 图像分割项目实践

    千次阅读 多人点赞 2019-05-15 01:40:30
    本文基于下面链接的项目, 实践一次基于Unet模型的图像分割. 个人在实现时遇到很多问题, 许多问题在网上并没有找到解答, 所以写下本文, 记录了在实现过程中遇到的问题和大部分代码的注解, 主要从代码逻辑入手, 分析...
  • 向AI转型的程序员都关注了这个号????????????人工智能大数据与深度学习 公众号:datayx一,手提包数据集数据集下载:用pytorch写FCN进行手提包的语义分割。train...
  • 作者:果果是枚开心果 ... 来源:知乎 著作权归作者所有。...自2012年AlexNet提出并刷新了当年ImageNet物体分类竞赛的世界纪录以来,CNN在物体分类、人脸识别、图像检索等方面已经取得了令人瞩目的成
  • 图像分割 | FCN网络

    千次阅读 2018-07-12 17:03:13
    本来这一篇是想写Faster-RCNN的,但是Faster-RCNN中使用了RPN(Region Proposal...RPN是一种全卷积网络,所以为了透彻理解这个网络,首先学习一下FCN(fully convolutional networks)Fully Convolutional Networks for...
  • 使用FCN的密集网的张量流实现以进行肝脏分割。 逐步配置 模型的所有基本配置和训练过程均在config.py中列出,并由EasyDict管理。 我们将配置参数定义为__C ,该参数在config.py定义。 注意:所有配置都可能会在一...
  • 图像分割FCN 算法笔记

    千次阅读 2019-11-08 14:17:27
    Berkeley团队于2014年提出Fully Convolutional Networks(FCN)方法用于图像语义分割,将图像级别的分类扩展到像素级别的分类。 FCN可以接受任意尺寸的输入图像,采用转置卷积层对最后一个卷积层的feature map进行上...
  • 该项目旨在使用完全卷积网络(FCN)标记图像的像素(也称为语义分割)。 它使用VGG-16实现转移学习并提取layer7的输出,然后使用1x1卷积,随后是几个转置的卷积层,并与跳过连接相结合以进行升采样。 网络架构如下:...
  • 飞桨PaddlePaddle图像分割七日打卡营之FCN学习心得FCN网络一些概念FCN网络结构FC层处理上采样的三种方法FCN实现参考 FCN网络 FCN是深度学习应用在图像分割的代表作, 是一种端到端(end to end)的图像分割方法, 让网络...
  • 深度学习图像分割算法—FCN代码实现

    万次阅读 多人点赞 2019-02-21 10:30:51
    FCN(全卷积网络) 原论文链接:https://arxiv.org/pdf/1411.4038.pdf 官方源代码:https://github.com/shelhamer/fcn.berkeleyvision.org截图如下 data文件夹:官方提供的四个数据集相关的文件,允许代码下载...
  • 图像分割任务中,传统的基于人工设计特征方法工作量大、复杂度高、分割精度较低,现有的基于全卷积神经网络(fully convolutional networks,FCN)的方法在分割边缘上不够精细。为了提高图像分割算法的分割精度,...
  • 本文基于动手深度学习项目讲解了FCN进行自然图像语义分割的流程,并对U-Net和Deeplab网络进行了实验,在Github和谷歌网盘上开源了代码和预训练模型,训练和预测的脚本已经做好封装,读者可以自行下载使用。...
  • 图像分割 | FCN数据集制作的全流程(图像标注)

    万次阅读 多人点赞 2017-06-06 15:52:07
    一 全卷积神经网络深度学习图像分割FCN)训练自己的模型大致可以以下三步:1.为自己的数据制作label;2.将自己的数据分为train,val和test集;3.仿照voc_lyaers.py编写自己的输入数据层。其中主要是如何制作自己的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,560
精华内容 3,424
关键字:

fcn图像分割