我最近在学习3D卷积神经网络时被问到这样一个问题,3D卷积在时间维度上空间距离是否一致呢?比如在处理视频数据时,视频的帧率是不同。
# 构建CNN神经网络
class CNN(nn.Module):
# 构造方法,用于创建卷积神经网络需要使用到的模块
def __init__(self):
super(CNN, self).__init__() # 继承父类的构造方法
self.c1 = nn.Conv2d(3, 16, (3, 3)) # 定义第一个卷积层,输入3个节点输出16个节点,3*3的卷积
self.c2 = nn.Conv2d(16, 32, (3, 3)) # 定义第二个卷积层,输入16个节点,输出32个节点,3*3的卷积
self.c3 = nn.Conv2d(32, 64, (3, 3)) # 定义第三个卷积层,输入32个节点,输出64个节点,3*3的卷积
self.b1 = nn.BatchNorm2d(16, affine=False) # 定义第一个归一化层
self.b2 = nn.BatchNorm2d(32, affine=False) # 定义第二个归一化层
self.b3 = nn.BatchNorm2d(64, affine=False) # 定义第三个归一化层
self.fc1 = nn.Linear(331776, 32) # 定义第一个全连接层
self.fc2 = nn.Linear(32, 2) # 定义第二个全连接层
# 构建计算数据集中一张图片数据数量的函数
def num_flat_features(self, x):
"""
计算数据集中数据数量的函数
:param x: 输入数据集
:return:
num_features:数据集中数据数量
"""
size = x.size()[1:] # 获取一个图片数据的大小
num_features = 1 # 初始化数量
for s in size:
num_features *= s
return num_features
# 构建前向传播函数
def forward(self, x):
"""
构建前向传播函数
:param x: 需要计算的数据
:return:
y_hat: 预测值
"""
p1 = F.relu(self.c1(x)) # 第一个卷积层的运算,先卷积,然后激活
b1 = self.b1(p1) # 第一个归一化层运算
p2 = F.relu(self.c2(b1)) # 第二个卷积层的运算,先卷积,然后激活
b2 = self.b2(p2) # 第二个归一化层运算
p3 = F.relu(self.c3(b2)) # 第三个卷积层的运算,先卷积,然后激活
b3 = self.b3(p3) # 第三个归一化层运算
m1 = F.max_pool2d(b3, 3, stride=3) # 最大池化层,(3, 3)的卷积核,步长为3
v1 = m1.view(-1, self.num_flat_features(m1)) # 将二维向量变为一维向量
h1 = self.fc1(v1) # 第一个全连接层
y_hat = torch.sigmoid(self.fc2(h1)) # 第二个全连接层的计算
# 返回预测值
return y_hat
时间维度和空间距离在3D卷积神经网络中是有区别的。在处理视频数据时,由于每个视频帧的帧率可能不同,可以应用3D卷积神经网络进行处理。具体解决方案如下:
以下是代码示例:
import torch.nn as nn
import torch.nn.functional as F
class CNN3D(nn.Module):
def __init__(self):
super(CNN3D, self).__init__()
self.conv1 = nn.Conv3d(3, 16, kernel_size=(5,3,3), padding=(2,1,1))
self.conv2 = nn.Conv3d(16, 32, kernel_size=(3,3,3), padding=(1,1,1))
self.conv3 = nn.Conv3d(32, 64, kernel_size=(3,3,3), padding=(1,1,1))
self.pool = nn.MaxPool3d(kernel_size=3, stride=3)
self.fc1 = nn.Linear(64*7*7, 120)
self.fc2 = nn.Linear(120, 2)
def forward(self, x):
p1 = F.relu(self.conv1(x))
p2 = self.pool(F.relu(self.conv2(p1)))
p3 = self.pool(F.relu(self.conv3(p2)))
v1 = p3.view(-1, self.num_flat_features(p3))
h1 = F.relu(self.fc1(v1))
y_hat = torch.sigmoid(self.fc2(h1))
return y_hat
def num_flat_features(self, x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
其中,Conv3d的参数含义分别是输入通道数、输出通道数、卷积核大小和padding大小。MaxPool3d的参数为池化核的大小和步长。在本例中,池化核大小为3,步长为3。在最后一层卷积层之后的输出需要通过view函数进行reshape,使其变为一维向量。