tensorflow cnn 小教程

tensorflow cnn 小教程

无论在nlp还是cv领域,cnn都是非常好用的工具,它擅长提取局部特征。

最简单的例子

import tensorflow as tf
tf.enable_eager_execution()
picture = tf.reshape([0.0, 0, 0, 0, 0, 1, 3, 0, 0, 2, 2, 0, 0, 0, 0, 0], [1, 4, 4, 1])
w = tf.reshape([1, 2, 0.5, 1], [2, 2, 1, 1])
out = tf.nn.conv2d(picture, w, [1, 1, 1, 1], padding="VALID")
print(tf.squeeze(picture))
print(tf.squeeze(w))
print(tf.squeeze(out))
# 下面是输出结果 ============================
tf.Tensor(
[[0. 0. 0. 0.]
 [0. 1. 3. 0.]
 [0. 2. 2. 0.]
 [0. 0. 0. 0.]], shape=(4, 4), dtype=float32)
tf.Tensor(
[[1.  2. ]
 [0.5 1. ]], shape=(2, 2), dtype=float32)
tf.Tensor(
[[ 1.   3.5  1.5]
 [ 4.  10.   4. ]
 [ 4.   6.   2. ]], shape=(3, 3), dtype=float32)

在这个例子中,输入一张单通道(channel)图片picture,它的shape是4*4。
我希望用一个2*2的卷积核w做卷积,看看卷积结果是什么样的。
输出结果可以看到,原始图像、卷积核以及卷积结果。这个结果,与我们心算的结果是一致的。

输出channel加一会怎样?

picture = tf.reshape([0.0, 0, 0, 0, 0, 1, 3, 0, 0, 2, 2, 0, 0, 0, 0, 0], [1, 4, 4, 1])
w1 = tf.reshape([1, 2, 0.5, 1], [2, 2, 1, 1])
w2 = tf.reshape([1.0, 1, 1, 1], [2, 2, 1, 1])
w = tf.concat([w1, w2], axis=-1)
out = tf.nn.conv2d(picture, w, [1, 1, 1, 1], padding="VALID")
print(tf.squeeze(picture))
print(tf.squeeze(tf.transpose(w, [3, 0, 1, 2])))
out = tf.transpose(out, [0, 3, 1, 2])
print(tf.squeeze(out))
# 下面是输出结果 ============================
tf.Tensor(
[[0. 0. 0. 0.]
 [0. 1. 3. 0.]
 [0. 2. 2. 0.]
 [0. 0. 0. 0.]], shape=(4, 4), dtype=float32)
tf.Tensor(
[[[1.  2. ]
  [0.5 1. ]]
 [[1.  1. ]
  [1.  1. ]]], shape=(2, 2, 2), dtype=float32)
tf.Tensor(
[[[ 1.   3.5  1.5]
  [ 4.  10.   4. ]
  [ 4.   6.   2. ]]
 [[ 1.   4.   3. ]
  [ 3.   8.   5. ]
  [ 2.   4.   2. ]]], shape=(2, 3, 3), dtype=float32)

稍加改变,输出通道数(channel)由1改为2,因此需要2个卷积核w1与w2。
合并两个卷积核w1与w2,得到w,其shape为[2*2*1*2],分别代表卷积核长2、宽2、输入通道数1、输出通道数2。
注意,这里是为了方便演示卷积计算。实际应用的时候,我们跳过分别定义w1与w2的过程,直接初始化w。
根据输出结果可以看出,2个卷积核在原始图像处理后,分别生成2张新的图像。其中,输出channel1,是与上一例子的结果完全一致的。
总结来说,有多少个输出通道channel,就会生成多少个新的图片。

输入channel加一会怎样?

channel1 = tf.reshape([0.0, 0, 0, 0, 0, 1, 3, 0, 0, 2, 2, 0, 0, 0, 0, 0], [1, 4, 4, 1])
channel2 = tf.reshape([0.0, 0, 0, 0, 0, 1, 3, 0, 0, 2, 2, 0, 0, 0, 0, 0], [1, 4, 4, 1])
picture = tf.concat([channel1, channel2], axis=-1)
w1 = tf.reshape([1, 2, 0.5, 1], [2, 2, 1, 1])
w2 = tf.reshape([1.0, 1, 1, 1], [2, 2, 1, 1])
w = tf.concat([w1, w2], axis=-2)
out = tf.nn.conv2d(picture, w, [1, 1, 1, 1], padding="VALID")
print(tf.squeeze(tf.transpose(picture, [3,0,1,2])))
print(tf.squeeze(tf.transpose(w, [3, 0, 1, 2])))
out = tf.transpose(out, [0, 3, 1, 2])
print(tf.squeeze(out))
# 下面是输出结果 ============================
tf.Tensor(
[[[0. 0. 0. 0.]
  [0. 1. 3. 0.]
  [0. 2. 2. 0.]
  [0. 0. 0. 0.]]
 [[0. 0. 0. 0.]
  [0. 1. 3. 0.]
  [0. 2. 2. 0.]
  [0. 0. 0. 0.]]], shape=(2, 4, 4), dtype=float32)
tf.Tensor(
[[[1.  1. ]
  [2.  1. ]]
 [[0.5 1. ]
  [1.  1. ]]], shape=(2, 2, 2), dtype=float32)
tf.Tensor(
[[ 2.   7.5  4.5]
 [ 7.  18.   9. ]
 [ 6.  10.   4. ]], shape=(3, 3), dtype=float32)

输入channel加一,既输入的图片具有2通道(channel),由channel1 与channel2 组成。实际中,RGB图是3通道。
卷积核需要由w1与w2组成,这是因为w1与w2分别在channel1与channel2上完成卷积。
通过w1 channel1卷积 与 w2 channel2卷积后,他们的结果再相加,得到最终结果。
从输出结果上看到本例的输出,正是上一例中输出的2通道输出的结果之和。
总结来说,输入图片有n个输入channel,一个卷积核需要有n个size*size的矩阵组合才能与之对应,在n个channel分别卷积后,再把结果相加,得到一个输出channel。

由以上可知卷积核维数[height, width, in_channels, output_channels]的意义了。

Depthwise Separable Convolution的优势

picture = tf.reshape([0.0, 0, 0, 0, 0, 1, 3, 0, 0, 2, 2, 0, 0, 0, 0, 0], [1, 4, 4, 1])
w = tf.reshape([1, 2, 0.5, 1], [2, 2, 1, 1])
point = tf.reshape([1.0], [1, 1, 1, 1])
out = tf.nn.separable_conv2d(picture, w, point, strides=[1, 1, 1, 1], padding="VALID")
print(tf.squeeze(picture))
print(tf.squeeze(w))
print(tf.squeeze(out))
# 下面是输出结果 ============================
tf.Tensor(
[[0. 0. 0. 0.]
 [0. 1. 3. 0.]
 [0. 2. 2. 0.]
 [0. 0. 0. 0.]], shape=(4, 4), dtype=float32)
tf.Tensor(
[[1.  2. ]
 [0.5 1. ]], shape=(2, 2), dtype=float32)
tf.Tensor(
[[ 1.   3.5  1.5]
 [ 4.  10.   4. ]
 [ 4.   6.   2. ]], shape=(3, 3), dtype=float32)

参考 https://blog.csdn.net/tintinetmilou/article/details/81607721
一张[4 * 4 * 3]的图片,用十个卷积核处理,参数量达到 2 * 2 * 3 * 10 = 120
改用depthwise separable convolution,参数量只需 2 * 2 * 3 + 3 * 10 = 42
可见,depthwise separable convolution可以大幅减少参数数量。

你可能感兴趣的:(tensorflow cnn 小教程)