网络性能提升的作用
1.提升模型准确率;
2.提高计算速度,加快收敛;
3.提高模型对为止数据的泛化能力。
一、使用复杂的模型
直接使用现成的模型,别人已经写好了。我们只需要站在巨人的肩膀上看世界就好~
这里使用的是ResNet模型。
1.1步骤
导入模块:from torchvision.models import resnet50
使用模型:net = resnet50(weights = ResNet50_Weights.IMAGENET1K_V1)
注意:根据pytorch安装的版本,参数会有所不同。旧版本参数用pretrained,新版本参数用weights。
1.2实现
import torch
from torchvision.models import resnet50
from torchvision.models import ResNet50_Weights
net = tesnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
print(net)
结果:
ResNet(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): Sequential(
(0): Bottleneck(
(conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
.......
(fc): Linear(in_features=2048, out_features=1000, bias=True)
)
)
二、继续训练
在前面已经提及了一点。就是在训练了很多次的模型基础上,以训练的模型为基础再训练模型,不会让计算机每次都从头开始训练,这样可以节省时间,也可以节省算力。
API:
model.load_state_dict(torch.load(model_path))
#简易版
import torch
import torcn.nn as nn
from torchvision import datasets,transforms
import torch.optim as optim
import os
#继续训练的训练集处理
transform_train = transforms.Compose([transforms.Totensor()])
#数据集加载
train_dataset = datasets.ImageFolder(
root = os.path.relpath(os.path.join(os.path.dirname(__file__),'dataset/Flower/train')),
transform = transform_train
)
#对训练数据集设置数据加载器
train_dataloder = DataLoder(train_dataset,batch_size = 32,shuffle = True,drop_last = True)
#定义你自己的网络结构
class MyNet(nn.Module):
def __init__(self):
......
def forward(self,x):
......
#定义自己的设备、批次、模型、学习率...
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = MyNet()
model.to(device)
epochs = 30
lr = 0.001
optimizer = optim.Adam(model.parameters(),lr = lr)
criterion = nn.CrossEntropyLoss()
#加载之前的模型
model.load_state_dict(torch.load(os.path.relpath(os.path.join(os.path.dirname(__file__),'models/last.pth'))))
#训练流程
for epoch in range(epochs):
model.train()
acc_total = 0
loss_total = 0
for i,(x,y) in enumerate(train_dataloder):
x = x.to(device)
y = y.to(device)
out = model(x)
loss = criterion(y,out)
optim.zero_grad()
loss.backward()
optim.step()
out1 = torch.argmax(out,dim=1)
acc_total += (out1==y).sum().item()
loss_total += loss.item()
torch.save(model.state_dict(),model_path)
print(f'进度{epoch/epochs},总损失{loss_total/len(train_dataloder.dataset)},准确率{acc_total/len(train_dataloder.dataset)}')
三、预训练
预训练的意义是利用迁移学习的优势,快速提升模型性能并减少训练成本。
import torch
from torchvision.models import resnet50
from torchvision.models import ResNet50_Weights
net = tesnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
print(net)
#保存预训练权重参数
torch.save(net.state_dict(),'resnet50.pth')
四、迁移学习
4.1意义
在别人已经测试的很完美的数据上进行修改,减少运算、节约成本,提高模型准确性,泛化能力。虽然别人的数据很完美,但是还要与我们自己的数据贴合起来,这样才能达到更好的效果,尤其是输入的数目和最后的输出分类数目一定要对应的上才行。
4.2步骤
(1)导入相关模块;
(2)进行预训练,保存预训练的权重结果;
(3)创建没有预训练的模型;
(4)修改预训练里面与我们数据不符合的数据信息;
(5)将预训练的权重参数加载出来,并删除输出不正确的全连接层fc;
(6)将预训练的权重参数更新到没有预训练的权重参数字典中;
(7)冻结不需要修改的权重参数即除了fc的所有参数;
(8)对fc进行筛选,进行梯度计算。
4.3实现
这是resnet50的输出fc结果: (fc): Linear(in_features=2048, out_features=1000, bias=True)
可以发现明显不对,因此需要修改,就有了上序步骤。
import torch
import torch.nn as nn
from torchvision.models import resnet50
from torchvision.models import ResNet50_Weights
import os
#创建没有预训练权重的resnet50模型
net_model = resnet50(weights = None)
#修改网络结构中不正确的信息
in_features = net_model.fc.in_features
print(in_features) #2048
net_model = nn.Linear(in_features, 3)
#加载预训练权重
resnet_path = os.path.relpath(os.path.join(os.path.dirname(__file__), 'model/resnet50.pth'))
pretrained_dict = torch.load(resnet_path)
pretrained_dict.pop('fc.weight')
pretrained_dict.pop('fc.bias')
#将预训练权重更新到没有预训练权重的模型中
#获取模型中所有可训练参数(如权重、偏置)的字典。
net_model_dict = net_model.state_dict()
net_model_dict.update(pretrained_dict)
#将保存的参数字典加载到模型中。
net_model.load_state_dict(net_model_dict)
#冻结参数
for name,param in net_model.named_parameters():
if name!='fc.weight' and name!='fc.bias':
param.requires_grad = False
#梯度计算fc--从模型中筛选出需要计算梯度的参数(即 requires_grad=True 的参数)
params_grad_true = filter(lambda x: x.requires_grad, net_model.parameters())
optimizer = torch.optim.Adam(params_grad_true, lr=0.001)
五、调整优化器和学习率
调整优化器就是冻结正确的参数,计算需要重新梯度计算的fc的权重和偏置。
优化器:
for name,value in pretrained_model.named_parameters():
if name!='fc.weight' and name!='fc.bias':
value.requires_grad = False
param_grade_true = filter(lambda x:x.requires_grad,pretrained_model.parameters())
optimizer = torch.optim.Adam(param_grade_true,lr = learning_rate)
学习率:
scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=30,gamma=0.1)
scheduler.step()
用于学习率衰减的调度器,作用是在训练过程中按固定间隔降低学习率,以帮助模型更好地收敛(避免因学习率过高导致震荡,或过低导致收敛缓慢)。