详解逆卷积操作–Up-sampling with Transposed Convolution

  • 2
  • 164 views
  • A+
所属分类:深度学习
摘要这篇文章详细介绍一下关于逆卷积的相关操作,查看卷积的系数与逆卷积的系数是否存在关系。

介绍

之前在介绍CNN的文章中,Convolutional Neural Networks(CNN)介绍–Pytorch实现,介绍了关于逆卷积的一些内容,但是感觉没有讲的很好。这次查到一篇文章,正好结合理解详细说一下,贴一下自己实验的结果。

参考链接 : Up-sampling with Transposed Convolution

建议可以看一下原文,我的理解可能还是会和原文有些偏差。

方法介绍

上面文章,强调的卷积和逆卷积的核心是:

  • 卷积是有一种,多对一的关系;
  • 逆卷积是有一种,一对多的关系;

可以简单看一下下面的示意图:

下面是进行卷积的过程,如卷积结果中122会和原来的9个数字有关系。

详解逆卷积操作--Up-sampling with Transposed Convolution

下面是逆卷积的过程,我们希望2通过逆卷积能与后面的9个数字有关。也就是说,进行逆卷积操作后,我们希望左上角的数字2希望和2和1有关系。那么如何达到这样的效果呢。

详解逆卷积操作--Up-sampling with Transposed Convolution

对于卷积的运算,其实我们可以转换为下面的矩阵乘法。我们将kernel排成下面的矩阵(4x16)。

这是原始的kernel,我们将其重新进行排列。(这里的图像有些不清楚,可以查看上面链接的原文结合进行查看)

详解逆卷积操作--Up-sampling with Transposed Convolution

重新排列后得到下面的矩阵:

详解逆卷积操作--Up-sampling with Transposed Convolution

具体关于下面矩阵的生成方法,其实就是把原始的kernel每一行展平,横着进行放置。

详解逆卷积操作--Up-sampling with Transposed Convolution

接着,我们把图像数据也进行展平,得到下面的数据。

详解逆卷积操作--Up-sampling with Transposed Convolution

最后,原始的进行卷积的操作,就相当于是下面的矩阵运算的操作了。最后只需要将结果的41还原回22的即可。(图片不清楚,建议查看原文)

详解逆卷积操作--Up-sampling with Transposed Convolution

上面的卷积过程,是一个416 × 161 = 41的过程。且我们可以看到,输出的每一个值都与原来的9个值有关,可以看到416的矩阵中有9个数字不为0,即每一行红色的个数。

于是,我们想到逆卷积的操作,相当于是164 × 41 = 16*1的一个过程,我们将上面的矩阵进行转置操作,在进行乘法。

详解逆卷积操作--Up-sampling with Transposed Convolution

上面的结果相当于是一个逆卷积的过程,可以看到input中的4个数字,如2会影响到最后output的9个数字,因为第一列有9个值不是0.

上面的过程,主要还是再强调,我们逆卷积和卷积是为了保持一个一对多和多对一的关系。卷积和逆卷积的系数都是要分别进行学习的,不是简单的转置的关系(下面的实验会有讲到)

在实际进行逆卷积的操作的时候,我们是会在input周围填充0,我们可以看下面的动图。动图来源 : https://github.com/vdumoulin/conv_arithmetic

详解逆卷积操作--Up-sampling with Transposed Convolution

可以看到,在填充后,input左上角的方框会被计算9次,相当于是和output的9个数字是有关系的。

实现结果

其实具体的实现的方式可以参考使用CNN在MNIST上实现简单的攻击样本,这里就是进行了简单的修改。

加载数据集

首先我们加载这次测试使用的数据集,使用MNIST的数据集;

  1. import torch
  2. import torch.nn as nn
  3. import torchvision
  4. import torchvision.transforms as transforms
  5. # Device configuration
  6. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  7. # Hyper-parameters 
  8. num_epochs = 5
  9. batch_size = 100
  10. learning_rate = 0.001
  11. # MNIST dataset
  12. train_dataset = torchvision.datasets.MNIST(root='./',
  13.                                            train=True,
  14.                                            transform=transforms.ToTensor(),
  15.                                            download=True)
  16. test_dataset = torchvision.datasets.MNIST(root='./',
  17.                                           train=False,
  18.                                           transform=transforms.ToTensor())
  19. # Data loader
  20. train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
  21.                                            batch_size=batch_size,
  22.                                            shuffle=True)
  23. test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
  24.                                           batch_size=batch_size,
  25.                                           shuffle=False)

 定义网络结构

我们使用下面一个简单的网络结构,我们先将图片通过卷积后池化进行压缩,接着希望通过逆卷积和逆池化进行还原。最后查看卷积的weight逆卷积的weight.

  • Conv->MaxPool->MaxUnpool->UnConv
  • 每一层图像大小的变化 28*28(input)->26*26(conv)->13*13(pool)->26*26(unpool)->28*28(output)
  1. # 搭建网络
  2. class CNNMNIST(nn.Module):
  3.     def __init__(self):
  4.         super(CNNMNIST,self).__init__()
  5.         self.conv1 = nn.Conv2d(in_channels=1,out_channels=1,kernel_size=3,stride=1,padding=0)
  6.         self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2,padding=0,return_indices=True)
  7.         self.unpool1 = nn.MaxUnpool2d(kernel_size=2,stride=2,padding=0)
  8.         self.unconv1 = nn.ConvTranspose2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)
  9.     def forward(self,x):
  10.         # encode
  11.         out1 = self.conv1(x)
  12.         out = out1.clone()
  13.         out,indices = self.pool1(out)
  14.         # deocde
  15.         out = self.unpool1(out,indices,output_size=out1.size())
  16.         out = self.unconv1(out)
  17.         return out
  18. # 网络的初始化
  19. model = CNNMNIST().to(device)
  20. print(model)
详解逆卷积操作--Up-sampling with Transposed Convolution

网络的训练

  1. # 定义优化器和损失函数
  2. criterion = nn.MSELoss(reduction='mean')
  3. optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
  4. # 进行训练
  5. model.train()
  6. total_step = len(train_loader)
  7. for epoch in range(num_epochs):
  8.     for i, (images, labels) in enumerate(train_loader):
  9.         # Move tensors to the configured device
  10.         images = images.to(device)
  11.         # Forward pass
  12.         outputs = model(images)
  13.         loss = criterion(outputs, images)
  14.         # Backward and optimize
  15.         optimizer.zero_grad()
  16.         loss.backward()
  17.         optimizer.step()
  18.         if (i+1) % 100 == 0:
  19.             # 计算Loss
  20.             print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
  21.                    .format(epoch+1, num_epochs, i+1, total_step, loss.item()))

重构的效果

我们使用网络进行重构,看一下最终的效果如何。

详解逆卷积操作--Up-sampling with Transposed Convolution

看卷积和逆卷积的系数

我们验证一下卷积和逆卷积的系数是否是转置的关系。

详解逆卷积操作--Up-sampling with Transposed Convolution

可以看到逆卷积的系数也是要进行训练得到的。

最后,还是十分建议阅读原文的,原文的链接如下:Up-sampling with Transposed Convolution

  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:2   其中:访客  1   博主  1

    • avatar clatterrr

      正被卷积玩得死去活来….
      话说卷积是组合数学的内容吧?还是具体数学…

        • avatar 王 茂南 Admin

          @clatterrr 这个分类我也不是很懂, 我之前看卷积是与图像处理有关. 我这里写的是介绍关于深度学习中(CNN)中卷积的操作.