深度学习的卷积运算(TensorFlow实现)

深度学习网络中,很重要的一种提取特征的手段,就是运用卷积运算。
在TensorFlow中实现二维卷积的运算,使用的是tf.nn.conv2d()函数,这一篇文章,主要讲解的就是这一个函数实现的具体的运算。


实际的计算不难,但是一涉及到多通道时,可能会感觉有点复杂。其实,和单通道的计算是一样的,只是多通道是多个并列计算。

下面一个图,很清楚地显示了卷积的计算过程






实际上,就是输入图像的每个通道和卷积核的每个通道对应的进行相乘相加,然后每个通道的值又加起来,最后得到输出。

TensorFlow实现卷积运算

TensorFlow中实现卷积运算的函数——tf.nn.conv2d()

函数形式(仅列出常用的参数):

tf.conv2d(input, filter, strides, padding)

input - 输入的图(图像或者特征图,下面统称为图像),其形式:[number, height, width, channels]

filter - 卷积核,其形式为:[height, width, in_channel, out_channel]。对于filter的参数,可以理解为:[卷积核的高,卷积核的宽,输入图像的通道数,卷积核的个数],有多少个卷积核,就会有多少个输出

strides - [1,y方向的步长, x方向的步长, 1]

padding - ‘SAME’,‘VALID’


下面编程实现:

#-*- coding:utf-8 -*-
import tensorflow as tf

input_x = tf.constant([
	[
		[[0.0, 1.0, 2.0],[1.0,1.0,0.0],[1.0,1.0,2.0],[2.0,2.0,0.0],[2.0,0.0,2.0]],
		[[0.0,0.0,0.0],[1.0,2.0,0.0],[1.0,1.0,1.0],[0.0,1.0,2.0],[0.0,2.0,1.0]],
		[[1.0,1.0,1.0],[1.0,2.0,0.0],[0.0,0.0,2.0],[1.0,0.0,2.0],[0.0,2.0,1.0]],
		[[1.0,0.0,2.0],[0.0,2.0,0.0],[1.0,1.0,2.0],[1.0,2.0,0.0],[1.0,1.0,0.0]],
		[[0.0,2.0,0.0],[2.0,0.0,0.0],[0.0,1.0,1.0],[1.0,2.0,1.0],[0.0,0.0,2.0]],
	],
])
filters = tf.constant([
	[
		[[1.0,-1.0,0.0],[1.0,0.0,1.0],[-1.0,-1.0,0.0]],
		[[-1.0,0.0,1.0],[0.0,0.0,0.0],[1.0,-1.0,1.0]],
		[[-1.0,1.0,0.0],[-1.0,-1.0,-1.0],[0.0,0.0,1.0]],
	],
])
bias = tf.constant(1.0,shape=[1])

filterinput = tf.reshape(filters, [3, 3, 3, 1])  # 将原始的filter转换成适合tf的输入的形式
res = tf.nn.conv2d(input_x, filterinput, strides=[1,2,2,1], padding='SAME')+bias

sess = tf.Session()
##print("result shape:", res.shape)
print(sess.run(res[:,:,:,0]))

最后结果:



思考:程序中是使用SAME的padding方式,若使用VALID呢? 答:由于不补零,卷积核的中心并不能遍历输入的图像,也就是说,滑动的范围减少。具体来讲,SAME的方式,由于补零,卷积核的第一个通道第一次滑动的中心,是在输入图像左上角的0开始的;而选择’VALID’之后,不会补零,则第一个滑动中心是之前0右下角的那个1。VALID的结果:


结语

之前使用深度学习网络,只是直接调用接口,对卷积的概念不是很清楚,特别是遇到多通道的情况。理清思路之后,感觉对深度网络提取特征的方法有了一点理解,也熟悉了tf实现卷积的方式,在看大牛写网络的时候,感觉更加清晰吧!