前言
需要用到3DCNN,于是找到了torch.nn.conv3d,网上太多人写参数解读,但没什么人能讲得清楚的,于是我边理解边写代码验证,得到了我想要的结果。
实例
用3DCNN的开篇之作来当作例子解读一下这个函数的参数,首先来看一下它的网络结构图,网上有很多人解读这篇文章,我就不细说了,这个网络中全是重复的3D卷积 → 池化操作,池化的操作和2D卷积没有区别,所以就讲3D卷积,拿下图红框中的来举例。- 输入形状是(7,60,40),7表示输入的图像帧数,60和40分别是宽和高。
- 过滤器形状是(7,7,3),3表示每次过滤器处理的图像帧数,7和7分别是卷积核宽和高。
- 输出形状是(5,54,34),5表示输出的图像帧数,54和34分别是宽和高。
注意:
1 这里的图像帧数并不是通道数,图像帧数就是图片数,而每张图片(RGB图像)又是有3个通道的。
2 如果对卷积核和过滤器的定义有疑问的,看参考文献[2](文中有卷积核和过滤器的概念)。
代码
import torch
import torch.nn as nn
from torch import autograd
# kernel_size的第哥一维度的值是每次处理的图像帧数,后面是卷积核的大小
m = nn.Conv3d(3, 3, (3, 7, 7), stride=1, padding=0)
input = autograd.Variable(torch.randn(1, 3, 7, 60, 40))
output = m(input)
print(output.size())
# 输出是 torch.Size([1, 3, 5, 54, 34])
首先明确一件事:假设矩阵的形状是(a,b,c),那么从右往左分别对应的是列、行、三维值。例如矩阵的形状是(4,3,6),意思是这是个三维矩阵,其中有4个二维矩阵,二维矩阵的形状是3 x 6。或者矩阵的形状是(5,4,7,3),意思是这是个四维矩阵,其中有5个三维矩阵,每个三维矩阵中有4个二维矩阵,二维矩阵的形状是7 x 3。而且形状中位置从左往右对应的是维度从高到低。
看一下中文文档
class torch.nn.Conv3d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
in_channels(int) – 输入信号的通道,就是输入中每帧图像的通道数
out_channels(int) – 卷积产生的通道,就是输出中每帧图像的通道数
kernel_size(int or tuple) - 过滤器的尺寸,假设为(a,b,c),表示的是过滤器每次处理 a 帧图像,该图像的大小是b x c。
stride(int or tuple, optional) - 卷积步长,形状是三维的,假设为(x,y,z),表示的是三维上的步长是x,在行方向上步长是y,在列方向上步长是z。
padding(int or tuple, optional) - 输入的每一条边补充0的层数,形状是三维的,假设是(l,m,n),表示的是在输入的三维方向前后分别padding l 个全零二维矩阵,在输入的行方向上下分别padding m 个全零行向量,在输入的列方向左右分别padding n 个全零列向量。
dilation(int or tuple, optional) – 卷积核元素之间的间距,这个看看空洞卷积就okay了
groups(int, optional) – 从输入通道到输出通道的阻塞连接数;没用到,没细看
bias(bool, optional) - 如果bias=True,添加偏置;没用到,没细看
这样解释参数,太不直观了,上一张画的不是很好的图再回过头来看代码
- (1,3,7,60,40)表示输入1个视频,每个视频中图像的通道数是3,每个视频中包含的图像数是7,图像的大小是60 x 40。
- (3,3,(3,7,7))表示的是输入图像的通道数是3,输出图像的通道数是3,(3,7,7)表示过滤器每次处理3帧图像,卷积核的大小是7 x 7。
- stride=1 表示stride=(1,1,1),在三维方向上步长是1,在宽和高上步长也是1。
- padding=0 表示padding=(0,0,0)表示在三维方向上不padding,在宽和高上也不padding。
总结
其实3DCNN和2DCNN的区别最大区别就是3DCNN每次可以融合多个图像的特征,而2DCNN只能融合一个图像的特征,理解3DCNN中同时处理多帧图像的时候可以类比2DCNN中同时处理多个通道。
参考文献
[1] pytorch中文文档
[2] 万字长文带你看尽深度学习中的各种卷积网络