近期开始学习Pytorch,在这里小小记录下。
由于是实现卷积神经网络,所以数据集统一使用CIFAR10。
首先,搭建最简单的卷积神经网络:
class Model(nn.Module):
def __init__(self) :
super().__init__()
# 序列化
self.model1=Sequential(
# 卷积层,参数依次为输入通道数、输出通道数、卷积核大小、填补大小
nn.Conv2d(3, 32, 5, padding=2),
# 最大池化层
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, padding=2),
nn.MaxPool2d(2),
# 扁平化
nn.Flatten(),
# 线性层,参数依次为输入特征数、输出特征数
nn.Linear(1024,64),
nn.Linear(64,10)
)
# 前向传播函数
def forward(self,x):
x=self.model1(x)
return x
主要是定义一个继承torch.nn.Module的类,然后定义初始化函数和forward函数,其中初始化函数中的序列化函数中操作可以自己搭配(注意参数维度要对应),这里推荐阅读Pytorch官方文档详细了解个函数功能。
实现了卷积类之后,就可以调用训练集进行训练,然后在测试集上得到最终训练结果:
# 训练集,参数分别为数据集路径、是否为训练集、进行的transform转换、是否需要在线下载
train_set=torchvision.datasets.CIFAR10(root='../dataset',train=True,transform=transforms.ToTensor(),download=False)
# 测试集
test_set=torchvision.datasets.CIFAR10(root='../dataset',train=False,transform=transforms.ToTensor(),download=False)、
# 加载训练集,参数依次为数据集、批次、是否打乱顺序
train_data=DataLoader(train_set,64,shuffle=True)
# 加载测试集
test_data=DataLoader(test_set,64,shuffle=True)
# 实例化卷积类
model=Model()
# 迭代次数
epoch_time=5
# 学习率
learn_rate=1e-2
# 交叉熵验证损失
loss=torch.nn.CrossEntropyLoss()
# 优化器,变量依次为待优化参数。学习率、动量
optim=torch.optim.SGD(model.parameters(),learn_rate,momentum=0.5)
for epoch in range(epoch_time):
print(f"---第{epoch+1}轮训练开始---")
# 训练步数
total_train_step = 0
# 测试精度
total_accuracy=0
# 训练集前固定写法(不写也无妨)
model.train()
for data in train_data:
images,targets=data
output=model(images)
# 计算损失
res_loss=loss(output,targets)
# 清零梯度
optim.zero_grad()
# 反向传播
res_loss.backward()
# 更新参数
optim.step()
total_train_step+=1
if total_train_step%100==0:
print(f"训练次数:{total_train_step},损失值:{res_loss}")
# 测试集固定写法
model.eval()
# 测试集不需要梯度下降,加快计算效率
with torch.no_grad():
for data in test_data:
images, targets = data
output = model(images)
accuracy=(output.argmax(1)==targets).sum()
total_accuracy+=accuracy
res_loss = loss(output, targets)
print(f"精确度={total_accuracy/len(test_set)}")
如果电脑有GPU的话还可以使用cuda()函数加快运算,这里不在赘述。
接下来实现稍微复杂一点的CNN结果,这是GoogleNet中的一个inception模块,主要是使用1x1的卷积来进行升降维,然后在多个尺寸上同时进行卷积再聚合。
class Inception(nn.Module):
def __init__(self,input):
super().__init__()
self.block1=nn.Sequential(
# 最大池化,参数依次为核大小、步长、填充
nn.MaxPool2d(3,stride=1,padding=1),
nn.Conv2d(input,24,1)
)
self.block2=nn.Conv2d(input,16,1)
self.block3=nn.Sequential(
nn.Conv2d(input,16,1),
nn.Conv2d(16,24,5,padding=2)
)
self.block4=nn.Sequential(
nn.Conv2d(input,16,1),
nn.Conv2d(16,24,3,padding=1),
nn.Conv2d(24,24,3,padding=1),
)
def forward(self,x):
output1 = self.block1(x)
output2 = self.block2(x)
output3 = self.block3(x)
output4 = self.block4(x)
outputs=[output1,output2,output3,output4]
# 合并这几个卷积结构处理得到的结果
return torch.cat(outputs,dim=1)
然后在主干网络上调用该模块:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.model1=nn.Sequential(
nn.Conv2d(3,10,5),
nn.MaxPool2d(2),
nn.ReLU())
self.inc1=Inception(10)
self.model2=nn.Sequential(
nn.Conv2d(88,20,5),
nn.MaxPool2d(2),
nn.ReLU())
self.inc2=Inception(20)
self.model3=nn.Sequential(
nn.Flatten(),
nn.Linear(2200,10)
)
def forward(self,x):
x=self.model1(x)
x=self.inc1(x)
x=self.model2(x)
x=self.inc2(x)
x=self.model3(x)
return x
最后是ResNet,主要使用跳跃连接来解决深层神经网络中出现的梯度消失问题。
首先实现残差结构:
class Res(nn.Module):
def __init__(self,input) -> None:
super().__init__()
self.model1=nn.Sequential(
nn.Conv2d(input,input,3,padding=1),
nn.ReLU(),
nn.Conv2d(input, input, 3, padding=1)
)
self.model2=nn.ReLU()
def forward(self,x):
y=self.model1(x)
y=x+y
return self.model2(y)
然后调用该结构形成完整的神经网络:
class Net(nn.Module):
def __init__(self) -> None:
super().__init__()
self.model=nn.Sequential(
nn.Conv2d(3,16,5),
nn.ReLU(),
Res(16),
nn.Conv2d(16,32,5),
nn.ReLU(),
Res(32),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(4608,10)
)
def forward(self,x):
return self.model(x)
这里在测试时需要注意图片尺寸和卷积处理大小要对应。
如果对自己实现的模型比较满意,也可以使用如下代码保存调用模型:
# 两个参数分别为模型、保存路径
torch.save(model,"mymodel.pth")
# 加载保存的模型
model=torch.load("mymodel.pth")
时间仓促,如有纰漏,请多指教。
以上。