Pytorch卷积神经网络
一、Pytorch一维卷积神经网络
import torch.nn as nn
nn.Conv1d( in_channels: int,
out_channels: int,
kernel_size: int,
stride: int, default = 1
padding: str/ int, default=0
dilation: int/ tuple, default=1
group: int, default=1
bias: bool, default = True
padding_mode: str, default = "zeros"
device: Ang,
dtype: Ang,
)
-
in_channels
:输入通道数,在一维卷积中由于不存在通道数,因此in_channels的数值为词向量的维度,如果一个单词用128维向量表示,那么in_channels = 128 -
out_channels
:输出通道数,表示经过卷积之后,一个词向量嵌入维度应该为多少。如果out_channels = 64,那么经过本次卷积之后的每个词的嵌入维度为64。【多个卷积层组合在一起时要求上一层的输出通道数与本次输入通道数一致】 -
kernel_size
:卷积核大小,表示本次卷积核的维度,一般是赋值为int类型,kernel_size=3,表示每次卷积计算操作涉及到3个词,也就是卷积核维度被设为(in_channels, kernel_size)。在Pytorch中,对于一条语句序列数据的每个词都是用一个列向量表示,在这一点不同于tensorflow,需要注意。
-
stride
:滑动步长,表示在卷积方向上滑动的步长。stride=2,表示在当前卷积的范围为123,下一个卷积范围就是345。 -
padding
:填补操作,表示在对特征矩阵剩余部分不足卷积时的操作。str --> padding =“valid”:表示不填充,剩余部分丢弃。 padding =“same”:表示在右侧填充之后要求输入输出序列长度一致
int --> padding = k: 表示在右侧填充k列
-
dilation
:设置卷积核元素之间的gap,dilation=k表示每个元素之间的gap=k,适合于空洞卷积操作 -
group
:设置群组卷积数 -
bias
:设置每个元素计算时是否加上偏置项 -
padding_mode
:设置填充元素,与padding配套使用,默认是zero
,也就是0填充,其他填充方式包括镜像填充、边缘填充、复制填充 -
device
:设置模型存放设备 -
dtype
:设置模型的计算数值类型
# 本网络实现功能为将通过训练含有10个样本的数据集得到每个语句的二元分类结果,其中每个样本序列长度为100,每个词的表示维度为128。
import torch.nn as nn
from torch import optim
import torch.nn.functional as F
class CNN1D(nn.Module):
def __init__(self):
super().__init__()
# 在一维卷积时,序列长度会随之发生改变,按照卷积输出公式可以计算得到,而词向量的表示维度就由out_channels确定
self.cnn1 = nn.Conv1d(128,64,3) # 要求输入的词向量维度为128, 卷积之后输出的词向量维度为64, 卷积核大小为128 * 3
self.cnn2 = nn.Conv1d(64,32,3) # 要求输入的词向量维度为64, 卷积之后输出的词向量维度为32, 卷积核大小为64 * 3
self.cnn3 = nn.Conv1d(32,16,3) # 要求输入的词向量维度为32, 卷积之后输出的词向量维度为16, 卷积核大小为32 * 3
# 池化层,kernel_size=2,表示在两个词对应位置中选最大保留,词向量维度不变
self.maxp = nn.MaxPool1d(kernel_size=2, stride=1)
# 因为本次输入的批次内样本数为10,因此最后需要输出的是10个预测结果,Linear实际是创建了(in_features, out_features)的矩阵
self.linear = nn.Linear(in_features = 16*93*10, out_features = 10)
def forward(self, data):
# print(data.size())
# data --> (10, 128,100)
data = self.cnn1(data)
# print("cnn1:", data.size())
# data --> (10, 64,98)
data = self.cnn2(data)
# print("cnn2:", data.size())
# data --> (10, 32,96)
data = self.cnn3(data)
# print("cnn3", data.size())
# data --> (10, 64,94)
data = self.maxp(data)
# print("maxp", data.size())
data = data.view(-1).contiguous()
# print("linear:", data.size())
out = F.sigmoid(F.relu(self.linear(data)))
return out
import torch
from torch import nn, optim
from MyCNN import CNN1D
epochs = 10000
batch_size = 10
model = CNN1D()
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters())
# 生成随机样本
inputs = torch.randn(batch_size, 100, 128) # 10个样本,每个样本序列长100,每个词的维度为128
inputs = inputs.permute(0, 2, 1) # Pytorch的一维卷积输入的信息应为(批次样本数,词向量维度,序列长度)
# 创建标签,即输出类别
targets = torch.randint(0, 2, size=(10,)) # 生成数值范围在[0,2)的正整数,也就是生成0和1,维度大小为(10,1)列向量
# 将数据分为训练集和测试集
train_inputs, train_targets = inputs[:8], targets[:8]
# 在这里有一个BUG,因为每次输入给模型的数据的样本量应该是统一的,为了模拟五折交叉验证计算,也应该是训练集分四次进去。不然就会报维度错误。
test_inputs, test_targets = inputs[8:], targets[8:]
# 设置本次计算的位置GPU(cuda/mps)/CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu')
# 训练阶段
for epoch in range(epochs):
# 将输入和标签加载到设备上
inputs = train_inputs.to(device)
targets = train_targets.to(device)
model.train()
predict = model(inputs)
# 计算损失
loss = criterion(predict.squeeze(), targets.float())
# 清零梯度,反向传播和更新模型参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每100轮输出一次训练结果
if (epoch + 1) % 100 == 0:
print(f"Epoch {epoch + 1}/{epochs}, Training Loss: {loss.item():.4f}")
# 测试阶段
model.eval()
# 将测试集转移到CPU设备上
test_inputs = test_inputs.to(device)
test_targets = test_targets.to(device)
# 通过模型生成预测
predictions = model(test_inputs)
# 将预测转换为类别
predicted_classes = (predictions.squeeze() > 0.5).long()
# 计算准确率
num_correct = (predicted_classes == test_targets).sum().item()
num_total = test_targets.shape[0]
accuracy = num_correct/num_total
print(f"Test Accuracy: {accuracy:.4f}")
二、Pytorch二维卷积神经网络
import torch.nn as nn
nn.Conv2d( in_channels: int,
out_channels: int,
kernel_size: int/tuple,
stride: int/tuple, default = 1
padding: str/ int/ tuple, default=0
dilation: int/ tuple, default=1
group: int, default=1
bias: bool, default = True
padding_mode: str, default = "zeros"
device: Ang,
dtype: Ang,
)
在二维卷积神经网络中的参数与一维卷积一致,但是参数可接纳数据类型发生一些更改,并且含有有一定的改变。
-
in_channels
:输入通道数,这个指的是一个样本中含有几个表示矩阵。比如RGB图像矩阵应该是含有3个通道,因为同一个位置的信息由3个数据进行表示,所以in_channels = 3。或者换个思路就与一维卷积一致:表示同一个位置的信息有几个量对其进行表示,这就是通道数真正的含义。一维卷积的一个词由词向量的维度表示,所以in_channels = 词向量维度。二维卷积更多是对图像的处理,所以in_channels一般指对于一个像素有几个量进行表示。
-
out_channels
:输出通道数,这个指的是输出通道的维度,也就是卷积之后对于一个信息有几个量表示,这个数值等于卷积核的个数。out_channels = 5说明卷积之后对于一个信息有5个量表示。 -
kernel_size
:卷积核大小,这个指的是在卷积操作中每个卷积核的尺寸维度。不同于一维卷积,二维卷积核含有长宽两方面的变化。kernel_size = 3 表示二维卷积核为3 * 3 的矩阵
kernel_size = (3,5) 表示二维卷积核为3 * 5的矩阵
-
stride
:卷积操作的步长,这个是卷积滑动时的移动的步长。同样含有两方面的移动步长stride = 3 表示二维卷积核在移动时,每移动一次,就向当前的方向走3个单位,比如当前为1,那么下一步位置为4
stride = (3,5) 表示二维卷积核在移动时,左右方向移动3个单位,当移动上下时,移动5个单位。
-
padding
:填充操作设置,该参数设置填充的行数str与一维一致
padding = 3 表示在右侧和下侧添加3个单位
Padding = (3,5) 表示在右侧添加3个单位 , 在下侧添加5个单位
-
其他与一维卷积一致
import torch.nn as nn
class CNN2D(nn.Module):
def __init__(self):
super().__init__()
self.cnn1 = nn.Conv2d(in_channels=3, out_channels=5, kernel_size=3)
self.cnn2 = nn.Conv2d(in_channels=5, out_channels=7, kernel_size=3)
self.cnn3 = nn.Conv2d(in_channels=7, out_channels=9, kernel_size=3)
self.maxp = nn.MaxPool2d(kernel_size=2, stride=1)
self.linear = nn.Linear(in_features=5*9*13*13, out_features=5)
def forward(self, data):
# data的size --> (5, 3, 20, 20)
# print("yuan:", data.size())
data = self.cnn1(data)
# print("cnn1:",data.size())
# data的size --> (5, 5, 28, 18)
data = self.cnn2(data)
# print("cnn2:", data.size())
# data的size --> (5, 7, 16, 16)
data = self.cnn3(data)
# print("cnn3:", data.size())
# data的size --> (5, 9, 14, 14)
data = self.maxp(data)
# print("maxp:", data.size())
# data的size --> (5, 9, 13, 13)
data = data.view(-1).contiguous()
# data的size --> (1, 5*9*13*13)
out = F.sigmoid(F.relu(self.linear(data)))
# out的size --> (1,sample_num)
return out
import torch
from torch import nn, optim
from MyCNN import CNN2D
epochs = 10000
batch_size = 10
model = CNN2D()
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters())
# 10个样本,每个样本3通道,每个通道20*20
inputs = torch.randn(batch_size, 3, 20, 20)
# 生成10个标签
targets = torch.randint(0,2, size = (batch_size,))
# 将数据分为训练集和测试集
train_inputs, train_targets = inputs[:5], targets[:5]
# 在这里有一个BUG,因为每次输入给模型的数据的样本量应该是统一的,为了模拟五折交叉验证计算,也应该是训练集分四次进去。不然就会报维度错误。
test_inputs, test_targets = inputs[5:], targets[5:]
# 设置本次计算的位置GPU(cuda/mps)/CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu')
# 训练阶段
for epoch in range(epochs):
# 将输入和标签加载到设备上
inputs = train_inputs.to(device)
targets = train_targets.to(device)
model.train()
predict = model(inputs)
# 计算损失
loss = criterion(predict.squeeze(), targets.float())
# 清零梯度,反向传播和更新模型参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每100轮输出一次训练结果
if (epoch + 1) % 100 == 0:
print(f"Epoch {epoch + 1}/{epochs}, Training Loss: {loss.item():.4f}")
# 测试阶段
model.eval()
# 将测试集转移到CPU设备上
test_inputs = test_inputs.to(device)
test_targets = test_targets.to(device)
# 通过模型生成预测
predictions = model(test_inputs)
# 将预测转换为类别
predicted_classes = (predictions.squeeze() > 0.5).long()
# 计算准确率
num_correct = (predicted_classes == test_targets).sum().item()
num_total = test_targets.shape[0]
accuracy = num_correct/num_total
print(f"Test Accuracy: {accuracy:.4f}")
三、Pytorch三维卷积神经网络
三维卷积网络实际上与二维卷积相差不大,一般适用于处理视频数据。不做代码与参数分析。