欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(pytorch-深度学习系列)CNN的多输入通道和多输出通道

程序员文章站 2022-05-26 19:23:27
...

CNN的多输入通道和多输出通道

之前的输入都视为二维数组,但是真实数据往往具有更高的维度,彩色图像有RGB三个颜色通道,那么这个图像(高为h,宽为w)可以表示为 3 ∗ h ∗ w 3*h*w 3hw的多维数组,一般将表示通道数的维(即3这一维)称为通道维

多输入通道

对于多维的输入,与二维的输入卷积操作类似,只是这里我们的卷积核需要构造成与输入数据通道数相同,从而使其能够与多通道数据进行互相关运算。

卷积的结果为将各个通道的互相关运算结果相加

例如,对与双通道数据,其维度为(2 * 3 * 3):
i n p u t = [ [ 0 1 2 3 4 5 6 7 8 ] [ 1 2 3 4 5 6 7 8 9 ] ] input = \begin{bmatrix} \begin{bmatrix} 0&1&2 \\ 3&4&5 \\ 6&7&8\end{bmatrix} \\ \\ \begin{bmatrix} 1&2&3 \\ 4&5&6 \\ 7&8&9\end{bmatrix} \end{bmatrix} input=036147258147258369

使用卷积核,其维度为(2 * 2 * 2):

k e r n e l = [ [ 0 1 2 3 ] [ 1 2 3 4 ] ] kernel = \begin{bmatrix} \begin{bmatrix} 0&1 \\ 2&3 \end{bmatrix} \\ \\ \begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} \end{bmatrix} kernel=[0213][1324]

那么运算为:
i n p u t ∗ k e r n e l = [ [ 0 1 2 3 4 5 6 7 8 ] [ 1 2 3 4 5 6 7 8 9 ] ] ∗ [ [ 0 1 2 3 ] [ 1 2 3 4 ] ] = [ 0 1 2 3 4 5 6 7 8 ] ∗ [ 0 1 2 3 ] + [ 1 2 3 4 5 6 7 8 9 ] ∗ [ 1 2 3 4 ] = [ 56 72 104 120 ] input * kernel = \begin{bmatrix} \begin{bmatrix} 0&1&2 \\ 3&4&5 \\ 6&7&8\end{bmatrix} \\ \\ \begin{bmatrix} 1&2&3 \\ 4&5&6 \\ 7&8&9\end{bmatrix} \end{bmatrix} * \begin{bmatrix} \begin{bmatrix} 0&1 \\ 2&3 \end{bmatrix} \\ \\ \begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} \end{bmatrix} = \begin{bmatrix} 0&1&2 \\ 3&4&5 \\ 6&7&8\end{bmatrix} * \begin{bmatrix} 0&1 \\ 2&3 \end{bmatrix} + \begin{bmatrix} 1&2&3 \\ 4&5&6 \\ 7&8&9\end{bmatrix} * \begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} = \begin{bmatrix} 56&72 \\ 104&120 \end{bmatrix} inputkernel=036147258147258369[0213][1324]=036147258[0213]+147258369[1324]=[5610472120]

实现多通道的互相关运算:

import torch
from torch import nn

def corr2d_multi_in(X, K):
    # 沿着X和K的第0维(通道维)分别计算再相加
    res = d2l.corr2d(X[0, :, :], K[0, :, :])
    for i in range(1, X.shape[0]):
        res += d2l.corr2d(X[i, :, :], K[i, :, :])
    return res

def corr2d(X, K):  
    h, w = K.shape
    Y = torch.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] = (X[i: i + h, j: j + w] * K).sum()
    return Y

输入数据验证上面的矩阵计算:

X = torch.tensor([[[0, 1, 2], [3, 4, 5], [6, 7, 8]],
              [[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
K = torch.tensor([[[0, 1], [2, 3]], [[1, 2], [3, 4]]])

corr2d_multi_in(X, K)

输出:

tensor([[ 56.,  72.],
        [104., 120.]])

多输出通道

当输入通道有多个时,因为我们对各个通道的结果做了累加,所以不论输入通道数是多少,输出通道数总是为1。
设卷积核输入通道数和输出通道数、高和宽分别为:
c i 、 c o 、 k h 、 k w c_i 、c_o、 k_h、k_w cicokhkw
如果希望得到含多个通道的输出,我们可以为每个输出通道分别创建一个核数组,其形状为:
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
在做互相关运算时,每个输出通道上的结果由卷积核在该输出通道上的核数组与整个输入数组计算而来。

该运算可以实现如下:

def corr2d_multi_in_out(X, K):
    # 对K的第0维遍历,每次同输入X做互相关计算。所有结果使用stack函数合并在一起
    return torch.stack([corr2d_multi_in(X, k) for k in K])

测试该运算:

K = torch.stack([K, K + 1, K + 2])
#(K+1)K中每个元素加一
K.shape # torch.Size([3, 2, 2, 2])

则现在的核数组为:
k e r n e l = [ [ [ 0 1 2 3 ] [ 1 2 3 4 ] ] [ [ 1 2 3 4 ] [ 2 3 4 5 ] ] [ [ 2 3 4 5 ] [ 3 4 5 6 ] ] ] kernel = \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} 0&1 \\ 2&3 \end{bmatrix} \begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} \end{bmatrix} \\\\ \begin{bmatrix} \begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} \begin{bmatrix} 2&3 \\ 4&5 \end{bmatrix} \end{bmatrix} \\\\ \begin{bmatrix} \begin{bmatrix} 2&3 \\ 4&5 \end{bmatrix} \begin{bmatrix} 3&4 \\ 5&6 \end{bmatrix} \end{bmatrix} \end{bmatrix} kernel=[[0213][1324]][[1324][2435]][[2435][3546]]

corr2d_multi_in_out(X, K)

输出:

tensor([[[ 56.,  72.],
         [104., 120.]],

        [[ 76., 100.],
         [148., 172.]],

        [[ 96., 128.],
         [192., 224.]]])