3. 多输入通道和多输出通道
前两节中,示例所用的输入和输出都是二维数组,但真实数据通常具有更高的维度:如彩色图像,在高和宽2个维度外还有RGB(红、绿、蓝)3个颜色通道。
假设彩色图像的高和宽分别是
h
h
h和
w
w
w(像素),那么,它可以表示为一个
3
×
h
×
w
3\times h\times w
3×h×w的多维数组。
我们将大小为3的这一维,称为通道(channel)维。
本节将介绍含多个输入通道或多个输出通道的卷积核。
3.1 muti-channels in
3.1.1 概念
当输入数据含多个通道时,需要构造一个输入通道数与输入数据的通道数相同的卷积核,从而能够与含多通道的输入数据做互相关运算。
假设输入数据的通道数为
c
i
c_i
ci,那么卷积核的输入通道数同样为
c
i
c_i
ci。
设卷积核窗口形状为
k
h
×
k
w
k_h\times k_w
kh×kw,
当
c
i
=
1
c_i=1
ci=1时,卷积核只包含一个形状为
k
h
×
k
w
k_h\times k_w
kh×kw的二维数组;
当
c
i
>
1
c_i > 1
ci>1时,会为每个输入通道分配一个形状为
k
h
×
k
w
k_h\times k_w
kh×kw的核数组。这
c
i
c_i
ci个数组在输入通道维上连结,可以得到一个形状为
c
i
×
k
h
×
k
w
c_i\times k_h\times k_w
ci×kh×kw的卷积核。由于输入和卷积核各有
c
i
c_i
ci个通道,可以在各个通道上对输入的二维数组和卷积核的二维核数组做互相关运算,再将这
c
i
c_i
ci个互相关运算的二维输出按通道相加,得到一个二维数组。这就是含多个通道的输入数据与多输入通道的卷积核做二维互相关运算的输出。
含2个输入通道的二维互相关计算,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/26cb0d3f0b64ae6102f9b56e14b3a073.png)
在每个通道上,二维输入数组与二维核数组做互相关运算,再按通道相加即得到输出。
图中阴影部分,为第一个输出元素及其计算所使用的输入和核数组元素:
(
1
×
1
+
2
×
2
+
4
×
3
+
5
×
4
)
+
(
0
×
0
+
1
×
1
+
3
×
2
+
4
×
3
)
=
56
(1\times1+2\times2+4\times3+5\times4)+(0\times0+1\times1+3\times2+4\times3)=56
(1×1+2×2+4×3+5×4)+(0×0+1×1+3×2+4×3)=56
3.1.2 代码示例
import tensorflow as tf
print(tf.__version__)
2.0.0
实现含多个输入通道的互相关运算:对每个通道做互相关运算,然后进行累加。
def corr2d(X, K):
"""
二维互相关计算
其中,tf.reduce_sum,示例如下:
x = tf.constant([[1, 1, 1], [1, 1, 1]])
print(tf.reduce_sum(x, axis=0))
print(tf.reduce_sum(x, axis=1))
print(tf.reduce_sum(x))
tf.Tensor([2 2 2], shape=(3,), dtype=int32)
tf.Tensor([3 3], shape=(2,), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
"""
h, w = K.shape
if len(X.shape)<=1:
X = tf.reshape(X, shape=(X.shape[0], 1))
Y = tf.Variable(tf.zeros((X.shape[0]-h+1, X.shape[1]-w+1)))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i,j].assign(tf.cast(tf.reduce_sum(X[i:i+h, j:j+w] * K), dtype=tf.float32))
return Y
def corr2d_multi_in(X, K):
"""多输入通道 二维互相关计算"""
return tf.reduce_sum([corr2d(X[i], K[i]) for i in range(X.shape[0])], axis=0)
X = tf.constant([[[0,1,2],[3,4,5],[6,7,8]],
[[1,2,3],[4,5,6],[7,8,9]]])
K = tf.constant([[[0,1],[2,3]],
[[1,2],[3,4]]])
corr2d_multi_in(X, K)
输出:
<tf.Tensor: id=377, shape=(2, 2), dtype=float32, numpy=
array([[ 56., 72.],
[104., 120.]], dtype=float32)>
3.2 multi-channels out
3.2.1 概念
在上述示例中,当输入通道为多个时,因为对各个通道的结果做了累加,所以输出通道数总是为1。
设卷积核输入通道数和输出通道数分别为
c
i
c_i
ci和
c
o
c_o
co,高和宽分别为
k
h
k_h
kh和
k
w
k_w
kw。
若希望得到含多个通道的输出,可以为每个输出通道分别创建形状为
c
i
×
k
h
×
k
w
c_i\times k_h\times k_w
ci×kh×kw的核数组。
将它们在输出通道维上连结,卷积核的形状即为
c
o
×
c
i
×
k
h
×
k
w
c_o\times c_i\times k_h\times k_w
co×ci×kh×kw。
在做互相关运算时,每个输出通道上的结果由卷积核在该输出通道上的核数组与整个输入数组计算而来。
3.2.2 代码示例
(1) 将核数组K
同K+1
(K
中每个元素加一)和K+2
连结在一起,构造一个输出通道数为3的卷积核:
K = tf.stack([K, K+1, K+2], axis=0)
K
输出:
<tf.Tensor: id=2177, shape=(3, 2, 2, 2), dtype=int32, numpy=
array([[[[0, 1],
[2, 3]],
[[1, 2],
[3, 4]]],
[[[1, 2],
[3, 4]],
[[2, 3],
[4, 5]]],
[[[2, 3],
[4, 5]],
[[3, 4],
[5, 6]]]], dtype=int32)>
其中,tf.reduce_sum
,示例如下:
x = tf.constant([1, 4])
y = tf.constant([2, 5])
z = tf.constant([3, 6])
print(tf.stack([x, y, z], axis=0))
print(tf.stack([x, y, z], axis=1))
print(tf.stack([x, y, z]))
输出:
tf.Tensor(
[[1 4]
[2 5]
[3 6]], shape=(3, 2), dtype=int32)
tf.Tensor(
[[1 2 3]
[4 5 6]], shape=(2, 3), dtype=int32)
tf.Tensor(
[[1 4]
[2 5]
[3 6]], shape=(3, 2), dtype=int32)
(2) 实现含多个输入及多个输出通道的互相关运算(即,输入数组X
与新的核数组K
做互相关运算):
def corr2d_multi_in_out(X, K):
return tf.stack([corr2d_multi_in(X, k) for k in K], axis=0)
corr2d_multi_in_out(X, K)
输出:
<tf.Tensor: id=1734, shape=(3, 2, 2), dtype=float32, numpy=
array([[[ 56., 72.],
[104., 120.]],
[[ 76., 100.],
[148., 172.]],
[[ 96., 128.],
[192., 224.]]], dtype=float32)>
此时,输出含有3个通道。其中,第一个通道的结果与之前输入数组X
与多输入通道、单输出通道核的计算结果一致。
3.3 1x1 convolution
3.3.1 概念
卷积窗口形状为 1 × 1 1\times 1 1×1( k h = k w = 1 k_h=k_w=1 kh=kw=1)的多通道卷积层,通常称之为 1 × 1 1\times 1 1×1卷积层,并将其中的卷积运算称为 1 × 1 1\times 1 1×1卷积。
因为使用了最小窗口,
1
×
1
1\times 1
1×1卷积失去了卷积层可识别高和宽维度上相邻元素构成模式的功能。
实际上,
1
×
1
1\times 1
1×1卷积的主要计算发生在通道维上。
使用输入通道数为3、输出通道数为2的 1 × 1 1\times 1 1×1卷积核的互相关计算,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/b9ba4021e11deb46eaff639e1a44ad3d.png)
值得注意的是:
输入和输出具有相同的高和宽;
输出中的每个元素来自输入中在高和宽上相同位置的元素在不同通道之间的按权重累加。
假设将通道维当作特征维,将高和宽维度上的元素当成数据样本,那么 1 × 1 1\times 1 1×1卷积层的作用与全连接层等价。
3.3.2 代码示例
使用全连接层中的矩阵乘法来实现 1 × 1 1\times 1 1×1卷积,并在矩阵乘法运算前后对数据形状做一些调整:
def corr2d_multi_in_out_1x1(X, K):
c_i, h, w = X.shape
c_o = K.shape[0]
X = tf.reshape(X, shape=(c_i, h*w))
K = tf.reshape(K, shape=(c_o, c_i))
Y = tf.matmul(K, X)
return tf.reshape(Y, shape=(c_o, h, w))
X = tf.random.uniform(shape=(3,3,3))
K = tf.random.uniform(shape=(2,3,1,1))
Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
tf.norm(Y1-Y2) < 1e-6
输出:
<tf.Tensor: id=3776, shape=(), dtype=bool, numpy=True>
1 × 1 1\times 1 1×1卷积层可以被当作保持高和宽维度形状不变的全连接层使用,由此可以通过调整网络层之间的通道数来控制模型复杂度。