一、前言
1、计算机视觉包含常用的四大任务:分类、识别、分割、检测等。
2、这些任务可以被称为下游任务,关键的上游任务是预训练模型的backbone。backbone是一个模型的特征提取层,也叫骨干网络。当涉及训练预模型时,有一个通用框架可以帮助我们快速构建和训练模型的backbone。这个框架可以适用于各种下游任务,并且易于定制和扩展。在本文中,我们将介绍这个通用框架的不同部分,并说明如何使用它来训练自己的模型。
二、具体步骤
接下来我将通过Resnet作为backbone来说明得到一个模型之后如何预训练来得到模型,包括数据加载和预处理、实例化模型并修改Fc(fully conneted layer)头、调整学习率策略、训练和验证函数等说明。
1、数据加载和预处理:通常我们可以加载一些官方的数据集或建立自己的数据集,这里有一些区别,比如官方的数据集往往经过预处理,可以直接加载函数,例如MNIST,ImageNet。而自己的数据集需要根据网络需求调整大小、channel等。无论是官方还是自己的数据集都需要适当的预处理,比如图像增强、归一化等等。下面是具体步骤:以官方的MNIST数据集为例
import torch
import torchvision
import torch.nn as nn
form torchvision import datasets
batch_size = 256 #批量大小
#预处理
transform = transforms.Compose(
[transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))]
)
transform_test = transforms.Compose(
[transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))]
)
#下载训练集
datasets_train = datasets.MNIST(root='./data',train=True,download=True,transform=transform)
datasets_test = datasets.MNIST(root='./data',train=False,download=True,transform=transform_test)
#加载训练集
train_loader = torch.utils.data.Dataloader(datasets_train,batch_size= batch_size,shuffle=True)
test_loader = torch.utils.data.DataLoader(datasets_test,batch_size=batch_size,shuffle=False)
若是接受自己的数据集:
from dataset.dataset import SeedlingData
dataset_train = SeedlingData(root='./data/train',transforms=transform,trian=True)
dataset_test = SeedlingData(root='./test/test', transforms=transform_test, train=False)
2、实例化模型:下载好模型源码,或者是选用torchvision.models里面已有的模型(包含Alexnet、densenet、inception、resnet、squeezenet、vgg),根据自己的任务调整分类头,下面以Resnet50为例:
from torchvision.models import resnet50
modellr = 1e-4 #learning rate
BATCHSIZE = 8
EPOCHS = 100
DEVICE = torch.device('cuda'if torch.cuda.is_vailable() else 'cpu') #使用GPU
classes = 10 #自己的类别数
criterion = nn.CrossEntropyLoss() #定义损失函数
model = Resnet50(Pretrained=True) #预训练的模型
print(model) #打印模型结构,方便修改全连接层
model.fc = nn.Linear(in_features=2048, out_features=classes, bias=True) #修改全连接层
model.to(DEVICE)
optimizer = optim.Adam(model_ft.parameters(), lr=modellr) #实例化Adam优化器,更新可学习参数
cosine_schedule = optim.lr_scheduler.CosineAnnealingLR(optimizer=optimizer,T_max=20,eta_min=1e-9) #余弦退火调整学习率
'''
可以用别的学习率衰减方法代替,例如
def adjust_learning_rate(optimizer,epoch):
modellrnew = modellr*(0.1**(epoch//50))
for param_group in optimizer.param_groups:
param_group['lr'] = modellrnew
'''
3、定义训练和验证函数:函数接受模型、周期、设备(GPU)、数据加载器、优化器等参数,多说无用,直接看代码:
def train(model,device,optimizer,epoch,train_loader):
model.train() #设置为训练模式,意味着模型中有BN层和Dropout会启用
sum_loss = 0
total_num = len(train_loader.dataset)
for batch_idx, (data, target) in enumerate(train_loader):
data,target = Variable(data).to(device),Variable(target).to(device)
output = model(data)
loss = criterion(output,target)
optimizer.zero_grad()
loss_backward()
optimizer.step()
print_loss = loss.data.item()
sum_loss += print_loss
if (batch_idx + 1) % 10 == 0: #每10个批次打印进度和损失
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),
100. * (batch_idx + 1) / len(train_loader), loss.item()))
ave_loss = sum_loss / len(train_loader)
print('epoch:{},loss:{}'.format(epoch, ave_loss))
def val(model,device,test_loader):
model.eval() #测试模式,不启用BN层和Dropout
test_loss = 0
correct = 0 #预测正确的样本数
total_num = len(test_loader.dataset)
print(total_num, len(test_loader))
with torch.no_grad():
for data, target in test_loader:
data, target = Variable(data).to(device), Variable(target).to(device)
output = model(data)
loss = criterion(output, target)
_, pred = torch.max(output.data, 1) #最优答案与标签是否相同
correct += torch.sum(pred == target)
print_loss = loss.data.item()
test_loss += print_loss
correct = correct.data.item()
acc = correct / total_num
avgloss = test_loss / len(test_loader)
print('\nVal set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
avgloss, correct, len(test_loader.dataset), 100 * acc))
开始训练:
# 训练
for epoch in range(1, EPOCHS + 1):
adjust_learning_rate(optimizer, epoch)
train(model_ft, DEVICE, train_loader, optimizer, epoch)
val(model_ft, DEVICE, test_loader)
torch.save(model_ft, 'model.pth') #保存权重
当然,如果你想只保留最好的权重,可以在验证函数那里修改,像这样:
ACC=0
# 验证过程
def val(model, device, test_loader):
global ACC
model.eval()
test_loss = 0
correct = 0
total_num = len(test_loader.dataset)
print(total_num, len(test_loader))
with torch.no_grad():
for data, target in test_loader:
data, target = Variable(data).to(device), Variable(target).to(device)
output = model(data)
loss = criterion(output, target)
_, pred = torch.max(output.data, 1)
correct += torch.sum(pred == target)
print_loss = loss.data.item()
test_loss += print_loss
correct = correct.data.item()
acc = correct / total_num
avgloss = test_loss / len(test_loader)
print('\nVal set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
avgloss, correct, len(test_loader.dataset), 100 * acc))
if acc > ACC:
torch.save(model_ft, 'model_' + str(epoch) + '_' + str(round(acc, 3)) + '.pth')
ACC = acc
以上,基本包含了整个训练流程。注意,backbone是和整个模型一起训练的,当然,我们可以通过不断优化训练方法(数据增强、学习率调整等等)来提高模型效果。一旦得到一个满意的模型后(评价模型的指标之前有提),可以拿它进行下游工作。
1、对于分类任务,可以将训练好的backbone模型与全连接层相连,以输出每个类别的概率分布。通过将输入样本传递给backbone模型,然后使用分类器对提取的特征进行分类,您可以得到输入属于每个类别的概率。最终,您可以选择具有最高概率的类别作为预测结果。
2、在目标检测任务中,您可以使用训练好的backbone模型来提取图像特征,并将这些特征传递给一个目标检测网络,如Faster R-CNN、YOLO或SSD。这个目标检测网络会在图像中定位和识别目标。通过联合训练backbone和目标检测网络,可以实现对图像中多个目标的检测和分类。
3、对于语义分割任务,使用训练好的backbone模型来提取图像特征,并将这些特征传递给一个分割网络,如U-Net或DeepLab。这个分割网络将利用backbone提取的特征来生成每个像素的语义分割结果,将图像中的每个像素分配给不同的类别,通过联合训练backbone和分割网络。
4、在目标识别任务中,您可以使用训练好的backbone模型来提取图像特征,并将这些特征传递给一个特征匹配或特征提取算法,如SIFT或ORB。这些算法可以在图像中寻找和识别特定目标的位置和姿态。通过结合backbone的特征提取能力和识别算法,可以实现对特定目标的识别和定位。
三、总结
以上为全部内容,觉得有用的亲可以点赞收藏哦,完整的框架内容可以从我的主页下载。