异想天开

What's the true meaning of light, Could you tell me why

tensorflow如何进行卷积操作(1)

日期:2017-12-09 10:39:28
  
最后更新日期:2017-12-09 20:05:59
卷积是一个数学概念,不止是在tensorflow存在。一直对神经网络的卷积操作的有点模糊不清,直到写了一个具体的tensorflow的卷积例子,才开朗。如果你已经了解了,神经网络卷积操作的含义,那么这篇日志你可以不看了。我使用的tensorflow的版本,为1.0.0版本,目前的最新版本版本是1.4.0。
tensorflow的tensor,即张量,我将它理解为向量,发现没有什么不妥,向量的概念更亲切。来写一个例子,这个例子的想法就是用tensorflow打印两个向量的卷积后的值。
来看1个通道,2个卷积核的例子,实现脚本如下:
[code lang="cpp"]
import tensorflow as tf
import numpy

print tf.__version__

sess = tf.Session()

conv1_weights = tf.constant([ [[[ 1.0, 5.0]], [[2.0, 6.0]]], [[[3.0, 7.0]],[[4.0, 8.0]]] ], shape=(2,2,1,2))
init = tf.global_variables_initializer()
sess.run( init )

data = numpy.ones( shape=(1, 3, 3, 1),dtype=numpy.float32)
conv = tf.nn.conv2d(data, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')

print "input:\n",data
print "\n"
print "filter:\n", sess.run( conv1_weights )

print "\n"
print "result:\n", sess.run( conv )

sess.close()
[/code]
首先先check一下,如果你运行上面的脚本,是否得到和我一样的结果:
input:
[[[[ 1.]
[ 1.]
[ 1.]]

[[ 1.]
[ 1.]
[ 1.]]

[[ 1.]
[ 1.]
[ 1.]]]]


filter:
[[[[ 1. 5.]]

[[ 2. 6.]]]


[[[ 3. 7.]]

[[ 4. 8.]]]]


result:
[[[[ 10. 26.]
[ 10. 26.]
[ 4. 12.]]

[[ 10. 26.]
[ 10. 26.]
[ 4. 12.]]

[[ 3. 11.]
[ 3. 11.]
[ 1. 5.]]]
ok,已经得到上诉结果。否则也可以不用看了。
回到开始的脚本,tensorflow的api设计非常简洁,不愧大神的设计。

* 脚本开始前会初始一个session,因为tensorflow计算步骤,是在session中执行的
[code lang="cpp"]
sess = tf.Session()
[/code]

* 获得一个大小为2x2x1x2的4维卷积核,这里用常量定义。向量各个维度的含义为:[filter_height, filter_width, in_channels, out_channels]
[code lang="cpp"]
conv1_weights = tf.constant([ [[[ 1.0, 5.0]], [[2.0, 6.0]]], [[[3.0, 7.0]],[[4.0, 8.0]]] ], shape=(2,2,1,2))
[/code]


* 将定义的全局变量初始化,比如上面只有conv1_weights的定义,具体的值是在执行完sess.run( init )后才有的。
[code lang="cpp"]
init = tf.global_variables_initializer()
sess.run( init )
[/code]

* 这里的输入数据的shape为[batch, in_height, in_width, in_channels]
[code lang="cpp"]
data = numpy.ones( shape=(1, 3, 3, 1),dtype=numpy.float32)
conv = tf.nn.conv2d(data, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')
[/code]
strides向量为步长,即在每一个维度的移动步长。strides为全是1的向量[1, 1, 1, 1],表示依次遍历整个batch * in_height * in_width * in_channels空间。
tf.nn.conv2d卷积操作时,有两种padding: SAME和VALID。
padding为VALID时,执行卷积操作时,不补齐数据。直接卷积。
padding为SAME时,执行卷积操作时,需要补齐数据,再卷积。补齐数据,让输出的图像的shape等于输入图片的shape。 比如3X3的输入图像,filter为2X2,则需要在输入图片缺少部分补齐0,然后卷积。

脚本构造的输入图片是虚拟的3X3全1的图,padding为SAME,需要用0补齐,成4X4。
$$
输入图像:
\left [ \begin{matrix} 1 & 1 & 1 & 0 \\
1 & 1 & 1 & 0\\
1 & 1 & 1 & 0 \\
0 & 0 & 0 & 0
\end{matrix} \right]

\\卷积核1:
\left [ \begin{matrix}1 & 2\\
3 & 4
\end{matrix} \right]

\\卷积核2:
\left [ \begin{matrix} 5 & 6\\
7 & 8
\end{matrix} \right]
$$
得到的结果为两张输出图像:
$$
\left [ \begin{matrix} 10 & 10 & 4 \\
10 & 10 & 4 \\
3 & 3 & 1
\end{matrix} \right]

\left [ \begin{matrix} 26 & 26 & 12 \\
26 & 26 & 12 \\
11 & 11 & 5
\end{matrix} \right]
$$
这个例子是1通道,2卷积核,通过卷积定义带入验算是正确的。