美文网首页
转置卷积

转置卷积

作者: 小黄不头秃 | 来源:发表于2022-09-23 02:12 被阅读0次

    (一)转置卷积

    我们之前的卷积神经网络中的卷积不会增输入的高和宽,通常要么不变,要么减半。如果我们想要增大图像只能使用padding的方法,但是padding并不是一个很好的想法,因为padding出来的值是0,是不参与计算的。而语义分割是基于像素级别的,也就是说如果我们使用普通的卷积的话,只会使得图片越来越小,然后就并不能进行很好的预测。

    转置卷积是一种卷积,能够用来增加输入的宽高。同卷积不同,卷积一般是做下采样,而它通常用作上采样。
    就是让输入的每一个值都和kernel做卷积,然后求和,变成想要的形状的output。有点和之前的卷积反过来差不多。如果是需要padding的话,需要增加在output上面。

    (1)为什么叫做“转置”呢?

    对于原来的卷积 Y = X * W,可以构造出一个V,使得卷积等价于举证乘法:Y' = V * X'。这里的Y' ,X' 对应的是X,Y的向量版本。

    转置卷积则等价于 Y'= Y^TX'

    !!!但是转置卷积不是卷积的逆运算。在数学中反卷积才是卷积的逆运算。

    (2)转置卷积的步骤

    这节课的padding和stride,感觉老师讲错了。所以我补充一个教程:
    【1】https://www.bilibili.com/video/BV1mh411J7U4?spm_id_from=333.337.search-card.all.click&vd_source=9e5b81656aa2144357f0dca1094e9cbe

    (二)代码实现

    import torch 
    from torch import nn 
    from d2l import torch as d2l
    
    def trans_conv(x,k):
        """转置卷积"""
        h,w = k.shape
        y = torch.zeros((x.shape[0]+h-1,x.shape[1]+w-1))
        for i in range(x.shape[0]):
            for j in range(x.shape[1]):
                # 元素乘以转置卷积核,结果累加
                y[i:i+h, j:j+w] += x[i,j] * k
        return y
    
    x = torch.tensor([[0.,1.],[2.,3.]])
    k = torch.tensor([[0.,1.],[2.,3.]])
    print(trans_conv(x,k))
    
    x = torch.tensor([[0.0,1.],[2.,3.]])
    k = torch.tensor([[0.,1.],[2.,3.]])
    print(trans_conv(x,k))
    
    # 使用torch中的高级API,获得相同的结果。
    x,k = x.reshape(1,1,2,2), k.reshape(1,1,2,2)
    tconv  = nn.ConvTranspose2d(1,1,kernel_size=2,bias=False)
    tconv.weight.data = k
    print(tconv(x))
    
    
    # 填充,步幅和多通道
    # 填充:填充为1时,即默认最外圈为填充,输出时删除第一行第一列,最后一行,最后一列
    tconv = nn.ConvTranspose2d(1,1,2,padding=1,bias=False)
    tconv.weight.data = k
    print(tconv(x))
    
    # 步幅为2
    tconv = nn.ConvTranspose2d(1,1,2,stride=4,bias=False)
    tconv.weight.data = k
    print(tconv(x))
    
    # 多通道,通道的变化是一样的
    x = torch.randn((1,10,16,16))
    conv = nn.Conv2d(10,20,kernel_size=6,padding=2,stride=2) # out_size = ((in_size - K + 2P) / S) +1
    tconv = nn.ConvTranspose2d(20,10,kernel_size=6,padding=2,stride=2) # out_size = (in_size -1)*S-2P+k
    print(tconv(conv(x)).shape) # torch.Size([1, 10, 16, 16])
    print(conv(x).shape) # torch.Size([1, 20, 8, 8])
    
    # 与矩阵乘法之间的关系
    X = torch.arange(9.0).reshape(3, 3)
    K = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
    Y = d2l.corr2d(X, K)
    Y
    
    def kernel2matrix(K):
        k, W = torch.zeros(5), torch.zeros((4, 9))
        k[:2], k[3:5] = K[0, :], K[1, :]
        W[0, :5], W[1, 1:6], W[2, 3:8], W[3, 4:] = k, k, k, k
        return W
    
    W = kernel2matrix(K)
    W
    
    Y == torch.matmul(W, X.reshape(-1)).reshape(2, 2)
    
    Z = trans_conv(Y, K)
    Z == torch.matmul(W.T, Y.reshape(-1)).reshape(3, 3)
    

    相关文章

      网友评论

          本文标题:转置卷积

          本文链接:https://www.haomeiwen.com/subject/zhnfortx.html