tf.nn.conv2d 你不知道的那些事儿

Posted 月来客栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tf.nn.conv2d 你不知道的那些事儿相关的知识,希望对你有一定的参考价值。


在处理图像类的数据集的时候,每张图片通常是用一个向量存储的,那么此时问题就来了:当我们在​​reshape​​的时候,到底该怎么填写维度呢? 举个例子吧!

现有两张RGB三通道的图片,假设第一张的三个通道对应的像素值矩阵如下,第二张将(48~95)同样按此排列。

R = [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ] G = [ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ] B = [ 32 33 34 35 36 37 38 39 30 41 42 43 44 45 46 47 ] \\beginaligned R=\\beginbmatrix 0&1 & 2 &3\\\\ 4&5 & 6&7 \\\\ 8&9&10&11\\\\ 12&13&14&15 \\endbmatrix G=\\beginbmatrix 16&17 & 18 &19\\\\20&21 & 22&23 \\\\24&25&26&27\\\\28&29&30&31 \\endbmatrix B=\\beginbmatrix 32&33 & 34 &35\\\\36&37 & 38&39 \\\\30&41&42&43\\\\44&45&46&47 \\endbmatrix \\endaligned R=0481215913261014371115G=16202428172125291822263019232731B=32363044333741453438424635394347

我们保存为如下形式:

x = [[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47]
[48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95]]

#每个向量表示一张图片

同时,有一尺寸为​​w=[2,2,3,1]​​的卷积核(为了计算方便,全设为1),则经过卷积计算后结果中的第一个值应该为:

0 ∗ 1 + 1 ∗ 1 + 4 ∗ 1 + 5 ∗ 1 + 74 + 138 = 222 0*1+1*1+4*1+5*1+74+138=222 01+11+41+51+74+138=222

当我们用​​tf.nn.conv2d​​​来计算卷积的时候,首先要做的就是将向量表示的图片,还原成矩阵形式来表示,那么​​reshape​​的方式到底是一下哪种呢?

​1. input = x.reshape(2,4,4,3)​

​2. input = x.reshape(2,3,4,4)​

第一感觉,肯定是第一种;因为在处理MNIST数据集的时候就是这样做的。但事实却是,在本文的情境下这是错的。what? 难道是第二种?此处先卖个关子,让我们用代码来证明第一种是错的。

我们知道图片的维度为​​4,4,3​​​,此处为两张图片,则形状为​​[2,4,4,2]​​​;经过卷积核为​​[2,2,3,1]​​​(无padding,步长为1)卷积后的形状为​​[2,3,3,1]​

x = np.arange(0, 96, 1).reshape(2, 48)
y = x.reshape(2, 4, 4, 3)
y = tf.convert_to_tensor(y, dtype=tf.float32)
w = tf.constant(value=1, shape=[2, 2, 3, 1], dtype=tf.float32)
conv = tf.nn.conv2d(y, w, padding=VALID, strides=[1, 1, 1, 1])
print(conv)
with tf.Session() as sess:
print(sess.run(conv))


结果:
Tensor("Conv2D:0", shape=(2, 3, 3, 1), dtype=float32)
[[[[ 102.]
[ 138.]
[ 174.]]

[[ 246.]
[ 282.]
[ 318.]]

[[ 390.]
[ 426.]
[ 462.]]]
# 为了排版,省去了第二张图片的结果

可以发现,能进行卷积计算,结果的形状也符合预期,可就是原本为222的地方,现在却变成了102,问题出在哪儿呢?

我们不妨输出两种​​reshape​​后的结果来看看(仅输出第一张图):

y = x.reshape(2, 4, 4, 3)
print(y[0])
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]

[[12 13 14]
[15 16 17]
[18 19 20]
[21 22 23]]

[[24 25 26]
[27 28 29]
[30 31 32]
[33 34 35]]

[[36 37 38]
[39 40 41]
[42 43 44]
[45 46 47]]]

y = x.reshape(2, 3, 4, 4)
print(y[0])

[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]

[[16 17 18 19]
[20 21 22 23]
[24 25 26 27]
[28 29 30 31]]

[[32 33 34 35]
[36 37 38 39]
[40 41 42 43]
[44 45 46 47]]]

发现没有,好像第二种​​reshape​​​方式才对啊,三个矩阵刚好对应三个通道。事实也确是这样,可偏偏​​tf.nn.conv​​​不依你。在​​Tenforflow​​​中,输入​​tf.nn.conv​​​的图片,必须将通道这个维度放在最后,也就是​​[4,4,3]​​​这种形式。这下该肿么办?此时​​np.transpose​​大喊一声,哪里逃,看我的!

于是正确的写法就该是:

​input = tf.reshape(2,3,4,4).transpose(0,2,3,1)​

注:0,1,2,3分别表示4个维度,此处表示将第2个维度换到最后,即把第三个通道放到最后一个维度。

x = np.arange(0, 96, 1).reshape(2, 48)
y = x.reshape(2, 3, 4, 4).transpose(0, 2, 3, 1)
print(y.shape)
y = tf.convert_to_tensor(y, dtype=tf.float32)
w = tf.constant(value=1, shape=[2, 2, 3, 1], dtype=tf.float32)
conv = tf.nn.conv2d(y, w, padding=VALID, strides=[1, 1, 1, 1])
print(conv)
with tf.Session() as sess:
print(sess.run(conv))

结果:

(2, 4, 4, 3)
Tensor("Conv2D:0", shape=(2, 3, 3, 1), dtype=float32)

[[[[222.]
[234.]
[246.]]

[[270.]
[282.]
[294.]]

[[318.]
[330.]
[342.]]]]

以上才是正确的​​reshape​​姿势!

注:


  1. ​tf.reshpe,tf.tranpose​​​同​​np.reshape,np.tranpose​​ ;
  2. 在处理MNIST数据集(仅有一个颜色通道)的时候用第一种方式​​reshape​​ 即可;
  3. 在处理CIFAR数据集的时候就需要用本文说得方式了;

随便多分析一下:

x = np.arange(0, 96, 1).reshape(2, 48)
y = x.reshape(2, 3, 4, 4)
print(y[0])

y = x.reshape(2, 3, 4, 4).transpose(0, 2, 3, 1)
print(y[0])

[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]

[[16 17 18 19]
[20 21 22 23]
[24 25 26 27]
[28 29 30 31]]

[[32 33 34 35]
[36 37 38 39]
[40 41 42 43]
[44 45 46 47]]]
------------------------------------------
[[[ 0 16 32]
[ 1 17 33]
[ 2 18 34]
[ 3 19 35]]

[[ 4 20 36]
[ 5 21 37]
[ 6 22 38]
[ 7 23 39]]

[[ 8 24 40]
[ 9 25 41]
[10 26 42]
[11 27 43]]

[[12 28 44]
[13 29 45]
[14 30 46]
[15 31 47]]]

可以看到,第一种形式​​[3,4,4]​​​每个矩阵表示一个颜色通道;第二种形式​​[4,4,3]​​ ,每一列表示一个颜色通道,一共三列。

更多内容欢迎扫码关注公众号月来客栈!

tf.nn.conv2d



以上是关于tf.nn.conv2d 你不知道的那些事儿的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow理解tf.nn.conv2d方法 ( 附代码详解注释 )

tf.nn.conv2d 与 tf.layers.conv2d

tf.nn.conv2d

tf.nn.conv2d 和 tf.nn.max_pool 中 padding 分别为 'VALID' 和 'SAME' 的直觉上的经验和测试代码

TF-卷积函数 tf.nn.conv2d 介绍

TF-卷积函数 tf.nn.conv2d 介绍