Tensorflow中的卷积函数
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
第一个参数input:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
第二个参数filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
第三个参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4
第四个参数padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式(后面会介绍)
第五个参数:use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
第六个参数:name参数用以指定该操作的name
返回:Tensor,这个输出,就是我们常说的feature map,shape仍然是[batch, height, width, channels]这种形式。
CNN中卷积的理解
这篇文章对CNN卷积的介绍较为详细, https://buptldy.github.io/2016/10/01/2016-10-01-im2col/
文中的两个图比较直观,图二中,input features,可以理解为一个3x3图片的3通道数据,卷积核为2x2大小三通道 2个卷积核。单通道的图片数据转化为矩阵时,是按照卷积核的大小展开为一维向量。图一的理解,则需要交换input和kernel的位置,output map逆时针旋转90度。
图一
图二
实践
用tensorflow的conv2d来验证图2的数据,其关键是输入和filter的数据的构造。
filter的维数[2, 2, 3, 2], 2x2维,3通道,2个卷积核,构造出的数据,不能直接按照卷积核的原始数据reshape得道,而是要重新排列,排列顺序如图。如果要到如图中第一个卷积核的数据则用filter_arg[:, :, 0, 0](也可见代码中的注释部分,通过直接赋值构建filter的值)。同理可以构造输入图片的数据,最后执行的结果和图中一致。
数据构建
import numpy as npimport tensorflow as tf input_arg = tf.constant([ [[1, 0, 1], [2, 2, 2], [0, 1, 1]], [[1, 0, 0], [1, 3, 1], [3, 2, 3]], [[0, 1, 3], [2, 1, 3], [2, 0, 2]]], dtype = tf.float32)# [filter_height, filter_width, in_channels, out_channels]#filter_arg = np.array(np.arange(24)).astype("float32")#filter_arg = np.reshape(filter_arg, [2, 2, 3, 2]).astype("float32")#filter_arg[:, :, 0, 0] = [[1, 1], [2, 2]]#filter_arg[:, :, 1, 0] = [[1, 1], [1, 1]] #filter_arg[:, :, 2, 0] = [[0, 1], [1, 0]]#filter_arg[:, :, 0, 1] = [[1, 0], [0, 1]]#filter_arg[:, :, 1, 1] = [[2, 1], [2, 1]] #filter_arg[:, :, 2, 1] = [[1, 2], [2, 0]] filter_arg = tf.constant([ [[[1, 1], [1, 2], [0, 1]], [[1, 0], [1, 1], [1, 2]]], [[[2, 0], [1, 2], [1, 2]], [[2, 1], [1, 1], [0, 0]]]], dtype = tf.float32) input_arg_normal = tf.reshape(input_arg, [1, 3, 3, 3]) filter_arg_normal = tf.reshape(filter_arg, [2, 2, 3, 2]) op1 = tf.squeeze(tf.nn.conv2d(input_arg_normal, filter_arg_normal, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='VALID'))with tf.Session() as sess: sess.run(tf.global_variables_initializer()) input_out = sess.run(input_arg_normal) print(input_out.shape) print(input_out) print("*" * 20) filter_out = sess.run(filter_arg_normal) print(filter_out.shape) print(filter_out) print("*" * 20) print(sess.run(op1))
运行结果
(1, 3, 3, 3)[[[[1. 0. 1.] [2. 2. 2.] [0. 1. 1.]] [[1. 0. 0.] [1. 3. 1.] [0, 1]], [3. 2. 3.]] [[0. 1. 3.] [2. 1. 3.] [2. 0. 2.]]]] ******************** (2, 2, 3, 2)[[[[1. 1.] [1. 2.] [0. 1.]] [[1. 0.] [1. 1.] [1. 2.]]] [[[2. 0.] [1. 2.] [1. 2.]] [[2. 1.] [1. 1.] [0. 0.]]]] ********************[[[14. 12.] [20. 24.]] [[15. 17.] [24. 26.]]]
参考文章
http://cs231n.github.io/convolutional-networks/
经典卷积计算图
作者:YANWeichuan
链接:https://www.jianshu.com/p/a1790d5f5770