FCN对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。
全卷积网络利用三种特殊技术
全卷积网络在结构上通常有编码器(Encoder)和解码器(Decoder)组成。编码器是一系列卷积层,如VGG和ResNet。编码器的目标是从图像中提取特征,解码器放大编码器的输出,使它和原来的图像大小相同。
卷积运算的输出是通过用滑动窗口来扫描输入的卷积核,以及执行元素相乘和求和来实现的。
一个1x1的卷积本质上是与一组维数的滤波器进行卷积:
1x1卷积有助于降低该层的维数。相同大小的全连接层会产生相同数量的特征。然而,用卷积层替换全连接层有一个额外的好处,在(测试模型期间,可以将任何大小的图像输入到训练好的网络中。
import numpy as np
import tensorflow as tf# 自定义初始化,默认设置种子为0
def custom_init(shape, dtype=tf.float32, partition_info=None, seed=0):return tf.random_normal(shape, dtype=dtype, seed=seed)# TODO:使用“tf.layers。conv2d '来重现' tf.layers. density '的结果。
# 设置 `kernel_size` 和 `stride`.
def conv_1x1(x, num_outputs):kernel_size = 1stride = 1return tf.layers.conv2d(x, num_outputs, kernel_size, stride, weights_initializer=custom_init)num_outputs = 2
x = tf.constant(np.random.randn(1, 2, 2, 1), dtype=tf.float32)
# 如果>的秩是2,则输入张量被‘tf. layer’压扁,然后再把它重塑回原来的秩作为输出
dense_out = tf.layers.dense(x, num_outputs, weights_initializer=custom_init)
conv_out = conv_1x1(x, num_outputs)with tf.Session() as sess:sess.run(tf.global_variables_initializer())a = sess.run(dense_out)b = sess.run(conv_out)print("Dense Output =", a)print("Conv 1x1 Output =", b)print("Same output? =", np.allclose(a, b, atol=1.e-5))
但是我发现并不能运行,程序报如下错误:
TypeError: conv2d() got an unexpected keyword argument 'weights_initializer'
经查询之后,tf.layers.dense
和tf.layers.conv2d
中并没有相关参数,于是将weights_initializer=custom_init
更改为kernel_initializer=custom_init
,程序正确输出如下:
Dense Output = [[[[-0.07399321 0.3901071 ][-0.21965009 1.1580395 ]][[ 0.29445606 -1.5524316 ][-0.7433553 3.9191186 ]]]]
Conv 1x1 Output = [[[[-0.07399321 0.3901071 ][-0.21965009 1.1580395 ]][[ 0.29445606 -1.5524316 ][-0.7433553 3.9191186 ]]]]
Same output? = True
1x1卷积函数注释:
tf.layers.conv2d(x, num_outputs, 1, 1, kernel_initializer=custom_init)
。
1
。1
。kernel_initializer=custom_init
:我们使用自定义初始化程序,因此dense层和卷积层中的权重相同。这就是保留空间信息的矩阵乘法运算。
我们可以使用转置卷积来创建全卷积网络的解码器。转置卷积本质上是一个反向卷积 ,其中前向和反向传播被调换。因此,我们称它为转置卷积。
有些人可能称它为反卷积,因为它撤销了前一个卷积,由于我们所做的只是调换前向传播和反向传播的顺序,这里的数学计算实际上和之前做的完全一样。因此,其可微性质保留了下来。而训练与之前的神经网络完全相同。
转置卷积有助于将上一层上采样到所需的分辨率或尺寸。假设有一个3x3的输入,并且希望将其上采样到所需的6x6尺寸。该过程涉及将输入的每个像素与内核或过滤器相乘。如果此过滤器的大小为5x5,则此操作的输出将为大小为5x5的加权内核。然后,该加权内核定义您的输出层。
但是,该过程的上采样部分由步幅和填充定义。在TensorFlow中,使用tf.layers.conv2d_transpose
,跨度为2和“ SAME”填充将导致输出尺寸为6x6。
如果我们有2x2输入和3x3内核;使用“ SAME”填充,并且跨度为2,我们可以预期输出尺寸为4x4。下图给出了该过程的想法。3x3加权内核(输入像素与3x3内核的乘积)由红色和蓝色正方形表示,它们之间的步幅为2。虚线正方形表示输出周围的填充。随着加权核的移动,步幅决定了输出的最终尺寸。这些参数的不同值将导致上采样输出的尺寸不同。
在TensorFlow中,API tf.layers.conv2d_transpose
用于创建转置的卷积层,程序如下:
import tensorflow as tf
import numpy as npdef upsample(x):"""对x应用两倍upsample并返回结果"""output = tf.layers.conv2d_transpose(x, 3, [2, 2], (2, 2), padding='SAME')return outputx = tf.constant(np.random.randn(1, 4, 4, 3), dtype=tf.float32)
conv = upsample(x)with tf.Session() as sess:sess.run(tf.global_variables_initializer())result = sess.run(conv)print('Input Shape: {}'.format(x.get_shape()))print('Output Shape: {}'.format(result.shape))
输出如下:
Input Shape: (1, 4, 4, 3)
Output Shape: (1, 8, 8, 3)
程序注释
使用tf.layers.conv2d_transpose(x, 3, (2, 2), (2, 2))
上采样。
全卷积网络使用的第三种特殊技术,是跳跃连接。一般来说 卷积或编码的一个缺点是,当你仔细观察某张图片,会导致范围缩小,从而失去了更大的图片。因此 即使我们要将编码器的输出解码回原始图像尺寸,一些信息却已经丢失。
跳跃连接是轻松保留信息的一种方式。跳跃连接工作的方式是使一层的输出与一个非相邻层连接。这里使用按元素添加操作 ,将来自编码器的池化层的输出与当前层的输出相结合,最终的结果连接到下一层。这些跳跃连接使网络可以使用来自多分辨率的信息,因此网络能够做出更精确的分割决策。
printf()函数优点在于可以格式化输出 格式: %['padding_character][-][width][.precision]type 所有的转换说明都是以%开始,如果想打印一个%符号,必须用%% ; 参数“'padding_character”是可选,它将被用来填充变量直至所指定的宽度,该参...
给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序,按GPLTGPLT....这样的顺序输出,并忽略其它字符。当然,四种字符(不区分大小写)的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按GPLT的顺序打印,直到所有字符都被输出。 输入格式: 输入在一行中给出一个长度不超过10000的、仅...
给定两个整数A和B,输出从A到B的所有整数以及这些数的和。 输入格式: 输入在一行中给出2个整数A和B,其中−100≤A≤B≤100,其间以空格分隔。 输出格式: 首先顺序输出从A到B的所有整数,每5个数字占一行,每个数字占5个字符宽度,向右对齐。最后在一行中按Sum = X的格式输出全部数字的和X。 输入样例:...
python面试题目 原文地址:https://www.usblog.cc/blog/post/justzhl/b5cc9a05c7d2 问题一:以下的代码的输出将是什么? 说出你的答案并解释。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Parent(object): x...
文章目录搭建实验平台使用Unity的准备工作在PC端安装连接Hololens软件Hololens设置开始连接吧绘制显示PC端网页监控...
将多次卷积和池化后的图像展开进行全连接,如下图所示。 全连接层需要把输入拉成一个列项向量 比如你的输入的feature map是2X2,那么就需要把这个feature map 拉成4X1的列向量,如果你的feature map 的channels是3,也就是你的输入是3X2X2,也就是相当于有了12个像素点,...
注意,前情提示: 本代码基于《Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)》 传送门Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)_你挚爱的强哥❤给你发来1条消息❤-CSDN博客 首先安装 cnpm i nodejs-websocket 在/a...
Ubuntu 配置自带桌面共享 1、在setting>>shareing>>remote 选择on 如果用ubunutu直接远程连接的话已经可以了, 2、在ubuntu下使用系统自带的remmina连接 vnc类型 直接输入ip地址 3、如果在windows下面连接的话需要把加密选项关闭 内容: 安装dconf-edito...
第四节 RabbitMQ在C#端的应用-客户端连接 原文:第四节 RabbitMQ在C#端的应用-客户端连接 版权声明:未经本人同意,不得转载该文章,谢谢 https://blog.csdn.net/phocus1/article/details/87357911 1.在VS2013中新建控制台程序,然后添加引用:.NE...