2D卷积和3D卷积的区别及pytorch实现

之前做医学图像分类时,老师有提到3D卷积,当时只是觉得3D卷积就是输入图像的3维的,把卷积核改成三维的就行,没有真正意识到3D卷积与2D卷积中的多通道卷积有什么区别,今天突然想到这个问题又查阅了很多资料才搞清楚里面的区别在哪,决定把自己总结的知识点记下来,以便于之后查看。(以下只是博主自己的理解,如有错误的地方,请一定要指出来,谢谢~)

下文的内容将会涉及到这幅图,来源于Learning Spatiotemporal Features with 3D Convolutional Networks(ICCV 2015):
原论文:Learning Spatiotemporal Features with 3D Convolutional Networks(ICCV 2015)

1 2D卷积

1.1 单通道卷积

以图像为例,单通道是指输入图像的channel为1,如MNIST数据集中的灰度图像。

  • 以MNIST数据集中的图像为例,输入图像的shape为(1,1,28,28),第一个‘1’表示batchsize为1,第二个‘1’表示图像channel为1,图像大小为28*28。
  • 单通道2D卷积中的卷积核shape为(1,kernel_height,kernel_width),因为卷积核的in_channel与输入图像的channel必须一致,输入图像的channel为1,所以卷积核的in_channel为1。卷积核大小为kernel_height×kernel_width。参数数量为:1×kernel_height×kernel_width×out_channels。
  • 单通道2D卷积的过程可以视为上图的中(a)的情况,卷积核在图像中从左向右,从上到下滑动来提取特征。卷积之后的output是2D的。

1.1.1 单通道卷积Pytorch实现

直接使用torchvision.datasets.MNIST()导入MNIST数据集,取其中一张图像为例,使用3×3的卷积核进行卷积:

import torch
import torchvision
import torch.nn as nn
##data是数据集中的一张图片
input_2d=data
print(input_2d.shape)  
##out: torch.Size([1, 1, 28, 28])

## '1'是in_channels,‘2’是out_channels
conv_2d_1=nn.Conv2d(1, 2, kernel_size=3,stride=1, padding=0)
output=conv_2d_1(input_2d)
print(output.shape)
##out:torch.Size([1, 2, 26, 26])
print(conv_2d_1.weight.size())
##out:torch.Size([2, 1, 3, 3])

1.2 多通道卷积

与单通道相对应,多通道是指输入图像的channel有多个,常见的是彩色图像,其有RGB三个通道,如CIFAR-10数据集中的图像。

  • 以CIFAR-10数据集中的图像为例,输入图像的shape为(1,3,32,32),‘1’表示batchsize,‘3’表示图像channel(R,G,B),图像大小为32*32。
  • 多通道2D卷积中的卷积核shape为(3,kernel_height,kernel_width),输入图像的channel决定了卷积核的in_channel。卷积核大小为kernel_height×kernel_width。参数数量为:3×kernel_height×kernel_width×out_channels,且每个通道的卷积核参数不同。
  • 多通道2D卷积的过程可以视为上图的中(b)的情况,卷积核在图像中从左向右,从上到下滑动来提取特征,卷积过程与单通道卷积区别不大。卷积之后的output是2D的。

1.2.1 多通道卷积Pytorch实现

直接使用torchvision.datasets.CIFAR10()导入CIFAR10数据集,取其中一张图像为例,使用3×3的卷积核进行卷积:

import torch
import torchvision
import torch.nn as nn
##data是CIFAR10数据集中的一个样本
input_3d=data
print(input_3d.shape)
##out: torch.Size([1, 3, 32, 32])

## '3'是in_channels,‘1’是out_channels
conv_2d_3=nn.Conv2d(3, 1, kernel_size=5,stride=1, padding=0)
output=conv_2d_3(input_3d)
print(output.shape)
##out:torch.Size([1, 1, 28, 28])
print(conv_2d_3.weight.size())
##out:torch.Size([1, 3, 5, 5])
print(conv_2d_3.weight)
##out:将每个通道的卷积核参数打印下来,发现不同通道参数不一样。
#Parameter containing:
#tensor([[[[-0.0600, -0.0141, -0.0144,  0.1019, -0.0315],
#          [ 0.0584,  0.0127, -0.0456, -0.0332, -0.0799],
#          [ 0.0907,  0.0177, -0.0280,  0.0516,  0.1063],
#          [-0.0778,  0.0547, -0.0803, -0.0821,  0.1050],
#          [ 0.0043, -0.0023,  0.0605,  0.0147,  0.0778]],

#         [[-0.0456,  0.0874,  0.1106, -0.0932, -0.1071],
#          [ 0.0710, -0.0980, -0.0349, -0.0049, -0.0561],
#          [ 0.0739, -0.0542, -0.0015,  0.0583,  0.0964],
#          [ 0.0017,  0.0645,  0.0116,  0.0480,  0.0664],
#          [-0.0622,  0.1145, -0.0708, -0.0958,  0.0587]],

#         [[ 0.0913, -0.0239,  0.0371, -0.0304,  0.0454],
#          [ 0.0646,  0.1053, -0.0504,  0.0908,  0.0729],
#          [ 0.0518,  0.0235, -0.0326, -0.0338, -0.0240],
#          [-0.0689, -0.0707,  0.0543,  0.1041, -0.0868],
#          [-0.0684, -0.0483, -0.0327, -0.0383, -0.0138]]]], requires_grad=True)

2 3D卷积

2.1 3D卷积特点

3D卷积同样有单通道卷积和多通道卷积,与2D卷积类似,这里不再赘述,只强调区别。

  • 同样以图像为例,3D卷积在医疗图像中使用较多,如CT,MRI等原始数据往往有多个切片构成。
  • 3D卷积中输入图像的shape为(1,channel,depth,height,weight),这里的depth是区别于2D卷积的关键,2D卷积的输入可以看出是3D卷积的特殊情况,即depth为1
  • 3D卷积中卷积核的shape为(input_channels , kernel_depth , kernel_height, kernel_width),与2D卷积相比,3D卷积的卷积核多了kernel_depth这个维度。卷积核大小为kernel_depth×kernel_height×kernel_width。参数数量为:input_channels×kernel_depth×kernel_height×kernel_width×out_channels,且每个通道的卷积核参数不同。
  • 3D卷积的过程可以视为上图的中(c)的情况,卷积核除了在3D图像中从左向右,从上到下滑动来提取特征外,还需要往一个额外的depth维度上滑动(可以看出除了在一个平面上往左右,上下滑动外,还要往里走,就是另外一个维度,想象一下,我不太会形容唉),因此3D卷积可以在空间中提取更强的特征信息,3D卷积后的output仍然是3D的。

2.2 3D卷积Pytorch实现

以CT数据集中的一个nii.gz文件为例,就是一个样本,利用SimpleITK中的SimpleITK.GetArrayFromImage()提取nii.gz中的array信息,可以得到该样本的shape为(301, 512, 512),即depth为301,height为512,weight为512。利用2×3×3的卷积核进行卷积:

import torch
import torchvision
import torch.nn as nn
import SimpleITK as sitk
import numpy as np
##这是一个CT数据集中的样本
filename='./coronacases_001.nii.gz'
itkimage = sitk.ReadImage(filename)
numpyImage = sitk.GetArrayFromImage(itkimage)
print(numpyImage.shape)
##out:(301, 512, 512)

##将输入reshape为网络输入数据的格式(batchsize,channel,depth,height,weight)
input_=torch.Tensor(numpyImage.reshape(1,1,301,512,512))
print(input_.shape)
##out:torch.Size([1, 1, 301, 512, 512])

##'1'是in_channels,‘2’是out_channels
##(2,3,3)分别对应kernel_depth,kernel_height,kernel_width
conv_3d=nn.Conv3d(1, 2, kernel_size=(2,3,3),stride=1, padding=0)
output=conv_3d(input_)
print(output.shape)
##out:torch.Size([1, 2, 300, 510, 510])
print(conv_3d.weight.size())
##out:torch.Size([2, 1, 2, 3, 3])
print(conv_3d.weight)
##out:每个通道的卷积核参数不同
#Parameter containing:
#tensor([[[[[-0.2320, -0.1497, -0.0779],
#           [-0.0511, -0.1489, -0.0866],
#           [ 0.1233, -0.2222,  0.0528]],
#          [[-0.0779,  0.2237, -0.0941],
#           [ 0.0026,  0.0426,  0.2323],
#           [ 0.2230, -0.0586,  0.2127]]]],

#        [[[[ 0.0393, -0.0342, -0.1338],
#           [ 0.0640,  0.0879, -0.2289],
#           [-0.0047, -0.1611,  0.2131]],
#          [[ 0.1573, -0.0108,  0.2327],
#           [-0.0824, -0.1601, -0.2348],
#           [ 0.1938, -0.0731,  0.1490]]]]], requires_grad=True)

参考资料:

  1. https://blog.csdn.net/strawqqhat/article/details/107655698
  2. https://blog.csdn.net/jer8888/article/details/102885963
  3. https://www.zhihu.com/question/266352189

猜你喜欢

转载自blog.csdn.net/gaoxiaoxue_/article/details/107978094