全卷积网络FCN详解

article/2025/9/16 18:44:21

入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。

目录

一、FCN提出原因

二、FCN的网络结构分析

三、基本网络结构的源码分析(FCN-32s)

1、conv_relu函数——用于定义卷积层以及该层的激活函数层

2、max_pool函数——用于定义池化层

3、fcn函数——用于生成train.prototxt和val.prototxt

四、FCN跳级结构原理解析

五、FCN跳级结构源码分析


一、FCN提出原因

为了解决图像分割这种像素级别的问题。

图像分类是图像级别的,一般使用CNN为基础框架进行分类,但是CNN难以应用于图像分割

原因:

(1)CNN在进行卷积和池化过程中丢失了图像细节,即feature map size渐渐减小,因此不能很好指出物体的具体轮廓,指出每个像素具体属于哪个物体,从而无法做到精确的分割。

(2)一般CNN分类网络都会在最后加入一些全连接层,经过softmax后就可以获得类别概率。但是这个概率是一维的,就是说只能标识整个图片(或整个网格内对象)的类别,不能标识每个像素点的类别,所以全连接方法并不适用于图像分割

因此FCN应运而生


二、FCN的网络结构分析

🌳传统的CNN网络结构如图的上部分,前面5层是卷积层,第6和7层都是长度为4096的一维向量,而第8层是长度为1000的一维向量(代表着1000种类别概率信息)

🌳而FCN将第6,7,8层这些原本是全连接层替换成卷积层,卷积核的大小(通道数,宽,高)分别为(4096,7,7)、(4096,1,1)、(1000,1,1),最后输出的是和输入一样的尺寸,输出尺寸类别种类数+1(背景)

因为这样一来网络里全是卷积层,所以才有这么个名字——全卷积网络

🌳并且FCN的输入可以是任意尺寸图像彩色图像

🌳简单来说,FCN就是将CNN最后的全连接层换成卷积层,输出和输入一样尺寸的已经标好每个像素类别概率值的图


三、基本网络结构的源码分析(FCN-32s)

FCN源码地址:

https://github.com/shelhamer/fcn.berkeleyvision.org 

我们以voc-fcn32s/net.py来阐述

1、conv_relu函数——用于定义卷积层以及该层的激活函数层

  • bottom:即该层的上一层的输出

  • nout:该卷积层输出的数目(即输出的特征图数目)

  • ks:卷积核的大小尺寸

  • stride:步长

  • pad:填充数

其中param的前部分是权重W的学习速率和衰减系数设置;

后部分是偏置b的学习速率(偏置不设置衰减系数)设置

def conv_relu(bottom, nout, ks=3, stride=1, pad=1):conv = L.Convolution(bottom, kernel_size=ks, stride=stride,num_output=nout, pad=pad,param=[dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)])return conv, L.ReLU(conv, in_place=True)

2、max_pool函数——用于定义池化层

全部采用最大池化法

def max_pool(bottom, ks=2, stride=2):return L.Pooling(bottom, pool=P.Pooling.MAX, kernel_size=ks, stride=stride)

3、fcn函数——用于生成train.prototxt和val.prototxt

🌳前部分是为了进行参数的设定

#用于生成train.prototxt和val.prototxt的函数
#输入参数split为'train'或'val'
def fcn(split):n = caffe.NetSpec() #使用pycaffe定义Net#参数设定pydata_params = dict(split=split, mean=(104.00699, 116.66877, 122.67892),seed=1337)if split == 'train':pydata_params['sbdd_dir'] = '../data/sbdd/dataset'pylayer = 'SBDDSegDataLayer'else:pydata_params['voc_dir'] = '../data/pascal/VOC2011'pylayer = 'VOCSegDataLayer'

🌳接下来设置数据和标签的载入等等

其中的module是模型名称,一般对应自己所写的一个.py文件(用于实现自己想要的该层的功能,在这里对应voc_layers.py文件)

    n.data, n.label = L.Python(module='voc_layers', layer=pylayer,ntop=2, param_str=str(pydata_params))

网络结构组装

🌳首先是前5层的卷积层

    # the base netn.conv1_1, n.relu1_1 = conv_relu(n.data, 64, pad=100)n.conv1_2, n.relu1_2 = conv_relu(n.relu1_1, 64)n.pool1 = max_pool(n.relu1_2)n.conv2_1, n.relu2_1 = conv_relu(n.pool1, 128)n.conv2_2, n.relu2_2 = conv_relu(n.relu2_1, 128)n.pool2 = max_pool(n.relu2_2)n.conv3_1, n.relu3_1 = conv_relu(n.pool2, 256)n.conv3_2, n.relu3_2 = conv_relu(n.relu3_1, 256)n.conv3_3, n.relu3_3 = conv_relu(n.relu3_2, 256)n.pool3 = max_pool(n.relu3_3)n.conv4_1, n.relu4_1 = conv_relu(n.pool3, 512)n.conv4_2, n.relu4_2 = conv_relu(n.relu4_1, 512)n.conv4_3, n.relu4_3 = conv_relu(n.relu4_2, 512)n.pool4 = max_pool(n.relu4_3)n.conv5_1, n.relu5_1 = conv_relu(n.pool4, 512)n.conv5_2, n.relu5_2 = conv_relu(n.relu5_1, 512)n.conv5_3, n.relu5_3 = conv_relu(n.relu5_2, 512)n.pool5 = max_pool(n.relu5_3)

🎈可以看到第一个卷积层中conv1_1采用pad=100进行填充,这是为了防止输入图片过小(待会1/32的输入图片尺寸的特征图过小),同时这也是FCN可以输入任意大小图片进行训练和测试的原因,但这同时填充这么大会引入噪声

🎈除了第一个卷积层中conv1_1采用pad=100进行填充外,conv1到conv5各卷积层的卷积核大小均为k=3,填充均为p=1(除了conv1_1),步长均为s=1(详见刚刚conv_relu函数的解释)

由公式

n_{\text {out }}=\left\lfloor\frac{n_{\text {in }}+2 p-k}{s}\right\rfloor+1

可知:在这样的条件下n_{\text {out }}=n_{\text {in }},即输入尺寸等于输出尺寸

🎈pool1-pool5各池化层的核大小均为k=2,填充均为p=0,步长均为s=2(详见刚刚max_pool函数的解释)

同样由上述公式可得出:n_{\text {out }}=n_{\text {in }}/2,即输出尺寸等于输入尺寸的1/2。

🎈所以通过第一个卷积层时,输出尺寸先增加了198,然后减半;接下来的2,3,4,5依次减半,即最后在增加198的基础上缩小了32倍的尺寸

在这里最后的输出是heat map(热图:高维特征图),不是我们通常说的普通的feature map

🌳接下来是对应CNN的全连接层的替换

# fully convn.fc6, n.relu6 = conv_relu(n.pool5, 4096, ks=7, pad=0)n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True)n.fc7, n.relu7 = conv_relu(n.drop6, 4096, ks=1, pad=0)n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True)n.score_fr = L.Convolution(n.drop7, num_output=21, kernel_size=1, pad=0,param=[dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)])n.upscore = L.Deconvolution(n.score_fr,convolution_param=dict(num_output=21, kernel_size=64, stride=32,bias_term=False),param=[dict(lr_mult=0)])n.score = crop(n.upscore, n.data)n.loss = L.SoftmaxWithLoss(n.score, n.label,loss_param=dict(normalize=False, ignore_label=255))return n.to_proto()

🎈第6层:先经过一次卷积后n_{\text {out }}=n_{\text {in }}-6,然后采用dropout技术(正则化,减弱过拟合,失活系数为0.5)[补充:dropout技术——随机让网络的某些节点不工作(输出置零),也不更新权重,但会保存下来,下次训练还会用,只是本次训练不参与bp传播,其他过程不变。]

🎈第7层:同样经过一次卷积,但是输入尺寸和输出尺寸一致,再次使用dropout技术,失活系数还是0.5

🎈第8层:score_fr层+上采样层

score_fr层:VOC数据集共21类,所以输出为21(如果是其他数据集,需要修改这个输出),不改变尺寸大小

上采样层:通过反卷积来进行上采样

由公式n_{\text {out }}=s(n_{\text {in }}-1)-2 p+kn_{\text {out }}=n_{\text {in }}+40

score层:通过crop函数对上采样层进行裁剪,得到和data层一样的大小,即最终输出等于最初输入

总结:采用反卷积层对最后一个卷积层的feature map进行上采样, 让它恢复到输入图像相同的尺寸,从而对每个像素都产生了一个预测, 同时又保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。


四、FCN跳级结构原理解析

🌳上述的网络结构其实已经可以实现图像分割了,但是直接将全卷积后的结果进行反卷积,得到的结果往往不太好看。

因此有了跳级结构——实现精细分割

🌳从上面的分析可以得到我们有1/32尺寸的heatMap(第5层卷积层的输出),1/16尺寸的featureMap(第4层卷积层的输出)和1/8尺寸的featureMap(第3层卷积层的输出)。1/32尺寸的heatMap进行上采样操作之后,不能很好地还原图像当中的特征(因为这样的操作还原的图片仅仅是conv5中的卷积核中的特征)。

🌳所以在这里向前迭代:

对于FCN-16s,首先对pool5 的输出进行2倍上采样获得2x upsampled feature,再把pool4的输出进行卷积和2x upsampled feature逐点相加,然后对相加的feature进行16倍上采样,并softmax prediction,获得16x upsampled feature prediction。

FCN-8s等原理与以上相同 


五、FCN跳级结构源码分析

这里以voc-fcn16s/net.py来阐述

其他的基本都和刚刚说的voc-fcn32s/net.py一样

以下是fully conv的代码

    # fully convn.fc6, n.relu6 = conv_relu(n.pool5, 4096, ks=7, pad=0)n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True)n.fc7, n.relu7 = conv_relu(n.drop6, 4096, ks=1, pad=0)n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True)n.score_fr = L.Convolution(n.drop7, num_output=60, kernel_size=1, pad=0,param=[dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)])n.upscore2 = L.Deconvolution(n.score_fr,convolution_param=dict(num_output=60, kernel_size=4, stride=2,bias_term=False),param=[dict(lr_mult=0)])n.score_pool4 = L.Convolution(n.pool4, num_output=60, kernel_size=1, pad=0,param=[dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)])#对pool4的卷积n.score_pool4c = crop(n.score_pool4, n.upscore2)n.fuse_pool4 = L.Eltwise(n.upscore2, n.score_pool4c,operation=P.Eltwise.SUM)#逐点相加n.upscore16 = L.Deconvolution(n.fuse_pool4,convolution_param=dict(num_output=60, kernel_size=32, stride=16,bias_term=False),param=[dict(lr_mult=0)])n.score = crop(n.upscore16, n.data)n.loss = L.SoftmaxWithLoss(n.score, n.label,loss_param=dict(normalize=False, ignore_label=255))return n.to_proto()

其中不同的对比


欢迎大家在评论区批评指正,谢谢~


http://chatgpt.dhexx.cn/article/WtpWCUTL.shtml

相关文章

四、全卷积网络FCN详细讲解(超级详细哦)

四、全卷积网络FCN详细讲解(超级详细哦) 1、全卷积网络(FCN)的简单介绍1.1、CNN与FCN的比较 2、FCN上采样理论讲解2.1、双线性插值上采样2.2、反卷积上采样2.3、反池化上采样 2、 FCN具体实现过程3、 FCN模型实现过程3.1、模型训练…

什么是前端,后端???什么是后台???

序言: 相信很多刚刚接触web开发不久,或者是对于web开发没有一个粗略认知的朋友们,有时候会被这样的一个问题迷惑:什么是前端,后端???什么是后台??&#xff1f…

Web后台管理系统

开发语言:C# 数据库:sql2008 登录页面 后台管理首页 部分操作页面 后台管理系统,界面简洁,大方,操作简单,所有功能可定制开发。 后台管理系统制作 如果你对编程感兴趣或者想往编程方向发展,可…

后台交互-首页

目录 一、小程序首页动态加载数据数据库准备后台环境搭建实现小程序数据交互 二、通过wxs将首页动态数据优化 一、小程序首页动态加载数据 数据库准备 首先要准备数据库以及数据 在本机数据库创建oapro数据库,然后导入运行数据库文件 /*Navicat Premium Data Trans…

Web后台管理框架收集,后台模板

Web 开发中几乎的平台都需要一个后台管理,但是从零开发一套后台控制面板并不容易,幸运的是有很多开源免费的后台控制面板可以给开发者使用,以下是我整理的一些UI框架模板,可以拿来稍加改造就能直接使用 ,简单实用 1、s…

后台管理系统,前端框架

1:vue-element-admin 推荐指数:star:55k Github 地址:https://github.com/PanJiaChen/vue-element-admin Demo体验:https://panjiachen.github.io/vue-element-admin/#/dashboard 一个基于 vue2.0 和 Eelement 的控制面板 UI 框…

Web后台快速开发框架

Web后台快速开发框架 Coldairarrow 目录 目录 第1章 目录 1 第2章 简介 3 第3章 基础准备 4 3.1 开发环境要求 4 3.2 基础数据库构建 4 3.3 运行 5 第4章 详细教程 6 4.1 代码架构 6 4.1.1总体架构 6 4.1.2基础设施层 …

10个开源web后台管理系统(一)

Web 开发中几乎的平台都需要一个后台管理,但是从零开发一套后台控制面板并不容易,幸运的是有很多开源免费的后台控制面板可以给开发者使用 10个开源WEB后台管理系统(一) 1. vue-Element-Admin vue-element-admin 是一个后台前端…

10个开源web后台管理系统(二)

Web 开发中几乎的平台都需要一个后台管理,但是从零开发一套后台控制面板并不容易,幸运的是有很多开源免费的后台控制面板可以给开发者使用 10个开源WEB后台管理系统(二) 10个开源WEB后台管理系统(一) 6.…

js前台与后台数据交互-前台调后台

网站是围绕数据库来编程的,以数据库中的数据为中心,通过后台来操作这些数据,然后将数据传给前台来显示出来(当然可以将后台代码嵌入到前台)。即: 下面就讲前台与后台进行数据交互的方法,分前台调…

EMQX的Web管理后台-Dashboard

一、引言 当EMQX安装好虽然可以使用Linux命令操作,但是作为一个MQTT的服务器,还是需要一个Web管理后台方便查看数据和操作。因此,EMQX启动后会默认加载一个名为「Dashboard」的插件,用以提供的一个后端 Web 控制台,通过…

web 前后台数据交互的方式

做web开发,很重要的一个环节就是前后台的数据的交互,数据从页面提交到contoller层,数据从controler层传送到jsp页面来显示。这2个过程中数据具体是如何来传送的,是本节讲解的内容。 首先说一下数据如何从后台的contorller层传送到…

(Web前端)后台管理系统框架收集

一、(Web前端)常用的后台管理系统框架 1、使用vue-element-admin https://panjiachen.github.io/vue-element-admin-site/zh/guide/ 模板建议使用 vueAdmin-template , 桌面端 electron-vue-admin 1.包含功能 登录/注销 权限验证 侧边栏…

什么是前端什么是后端?什么是前台后台

前台:呈现给用户的视觉和基本的操作。简单来说就是访问网站的人看到的内容和页面。下图以百度为例,我们看到的界面就是前台 后台:指程序的使用人员,管理人员经过密码或其他验证手段之后才可以看到的内容,一般可以进行一…

什么是前端、JavaWeb、Web前端、前台、后台

JavaWeb是java开发中的一个方向 Java有搞安卓的,搞Web的,搞嵌入式的,等等。。 JavaWeb就是指搞web方向的,JavaWeb分两块一块是服务器端 叫后端,另一块叫前端,也就是Web前端。前端就是用户能看到的部分&am…

(Web前端)十分优秀的后台管理框架收集

Web 开发中几乎的平台都需要一个后台管理,但是从零开发一套后台控制面板并不容易,幸运的是有很多开源免费的后台控制面板可以给开发者使用,以下是我整理的一些UI框架模板,可以拿来稍加改造就能直接使用 1、vue-element-admin h…

web 后台学习介绍

什么是后台 后台,指网站后台,有时也称为网站管理后台,是指用于管理网站前台的一系列操作,如:产品、企业信息的增加、更新、删除等。动态网页一般指的就是后台和静态页面结合的网页。例如,我们最常用的淘宝…

有关Web前端和后台的部分简介

有关Web前端和后台的部分简介 Web前端简述 1:Web前端是什么 Web前端技术包括JavaScript,ActionScript,CSS,xHTML等“传统”技术与Adobe RIA,Google Gears,以及概念性较强的交互式设计,艺术性设计较强的视觉设计等等。它所涵盖的…

java oozie任务状态_Oozie工作流分析

我们在实际的生成操作中经常需要将一些任务在晚上开启进行定时执行,或者多个作业,例如hive,mapreduce,shell等任务的组合调用。 我们可以使用linux的contab spervisor inotify-tool进行任务的配值,但是操作起来麻烦,而且没有可视…

Oozie--安装部署

Oozie的部署 1、上传解压2、配置Hadoop代理用户3、重启Hadoop集群4、解压lib包5、引入extjs6、修改oozie配置文件7、创建oozie元数据库8、初始化oozie为什么要将oozie的这些jar包放到hdfs上? 9、生成web项目10、配置环境变量11、Oozie的启动与关闭12、修改界面默认时区 参考&a…