resnet18实现猫狗分类
先简单说⼀下整体流程,利⽤pytorch训练模型并转化为onnx格式,然后配置好dlinfer,利⽤cv22infer在cv22平台量化序列化模型,展开推理
1训练模型
1.1处理数据集
参考图⽚下载地址:
1.1.1⾸先继承写⼀个继承⾃dataset的类
#继承了Dataset的类
class DogCat(data.Dataset):
def__init__(self, root, transform=None, train=True, test=False):
'''root表⽰⽤于训练的图⽚地址,前70%⽤于训练,后30%⽤于测试
'''
imgs =[os.path.join(root, img) for img in os.listdir(root)] #imgs是⼀个list,list中放(编号,图⽚地址)
st:#如果是test集
imgs =sorted(imgs, key=lambda x: int(x.split('.')[-2].split('/')[-1]))
else: #如果是train集
imgs =sorted(imgs, key=lambda x: int(x.split('.')[-2]))
imgs_num =len(imgs)
st:
self.imgs =imgs
else:
random.shuffle(imgs)
ain:
self.imgs =imgs[:int(0.7*imgs_num)]#self.imgs表⽰前百分之七⼗的图⽚
else:
self.imgs =imgs[int(0.7*imgs_num):]#self.imgs表⽰除了前百分之七⼗的图⽚
# 作为迭代器必须有的⽅法,可以⽤[]符号读取数据
def__getitem__(self, index):
img_path =self.imgs[index]
st:
label =int(self.imgs[index].split('.')[-2].split('/')[-1])
else:
label =1if'dog'in img_path.split('/')[-1] else0# 狗的label设为1,猫的设为0
data =Image.open(img_path)
data =ansform(data)
return data, label
def__len__(self):
return len(self.imgs)
1.1.2把传⼊的图⽚集转换为Tensor并且改变格式
# 对数据集训练集的处理
transform_train = transforms.Compose([
transforms.Resize((256, 256)), # 先调整图⽚⼤⼩⾄256x256
transforms.RandomCrop((224, 224)), # 再随机裁剪到224x224
transforms.RandomHorizontalFlip(), # 随机的图像⽔平翻转,通俗讲就是图像的左右对调
transforms.ToTensor(), #图⽚转换为Tensor
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.2225)) # 归⼀化,数值是⽤ImageNet给出的数值
])
# 对数据集验证集的处理
transform_val = transforms.Compose([
transform_val = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
])
device = torch.device('cuda'if torch.cuda.is_available() else'cpu') # 若能使⽤cuda,则使⽤cuda
trainset = DogCat('/mnt/ssd0/zhangwentao/train', transform=transform_train)#这是我图⽚的地址
valset = DogCat('/mnt/ssd0/zhangwentao/train', transform=transform_val)
#继承了dataset dataset ⼀捆有多⼤数据顺序多线程输⼊,=0表⽰单线程trainloader = torch.utils.data.DataLoader(trainset, batch_size=20, shuffle=True, num_workers=0)
valloader = torch.utils.data.DataLoader(valset, batch_size=20, shuffle=False, num_workers=0)
1.2修改⽹络模型
class Net(nn.Module):
'''pytorch的resnet18接⼝的最后⼀层fc层的输出维度是1000。这明显不符合猫狗⼤战数据集,
因为猫狗⼤战数据集是⼆分类的,所以最后⼀层fc输出的维度已经是2才对。
因此我们需要对resnet18进⾏最后⼀层的修改。
'''
def__init__(self, model):
super(Net, self).__init__()
# 取掉model的后1层
self.Linear_layer =nn.Linear(512, 2) # 加上⼀层参数修改好的全连接层
def forward(self, x):
x =snet_layer(x)
x =x.view(x.size(0), -1)
x =self.Linear_layer(x)
return x
'''具体参考完整代码,这⾥仅展⽰如何使⽤⽹络模型
model = Net(resnet18(pretrained=True))
model = (device)#转到gpu上运⾏
'''
1.3开始训练
''' for epoch in range(1):
train(epoch)训练
val(epoch) 验证,算损失函数
'''
#训练epoch次
def train(epoch):
scheduler.step() #按照Pytorch的定义是⽤来更新优化器的学习率的
train_acc =0.0#准确率
for batch_idx, (img, label) in enumerate(trainloader):
image =Variable(img.cuda())#放到gpu上
label =Variable(label.cuda())#放到ppu上
<_grad()#意思是把梯度置零,也就是把loss关于weight的导数变成0.
out =model(image) #投喂图⽚
loss =criterion(out, label)#利⽤交叉熵损失函数算出out和label的差别
loss.backward()#反向传播
optimizer.step()
train_acc =get_acc(out, label)#获得准确率
print("Epoch:%d [%d|%d] loss:%f acc:%f"%(epoch, batch_idx, len(trainloader), an(), train_acc)) #验证准确率
def val(epoch):
print("\nValidation Epoch: %d"%epoch)
model.eval()#进⼊推理模式
total =0
correct =0
_grad():
_grad():
for batch_idx, (img, label) in enumerate(valloader):
image =Variable(img.cuda())
label =Variable(label.cuda())
out =model(image)
_, predicted =torch.max(out.data, 1)
total +=image.size(0)
correct +=predicted.data.eq(label.data).cpu().sum()
print("Acc: %f "%((1.0*correct.numpy()) /total))
1.4完整代码
variable used in lambdasnet import resnet18
import os
import random
from PIL import Image
import torch.utils.data as data
import numpy as np
ansforms as transforms
import torch
as nn
import torch.optim as optim
from torch.autograd import Variable
from torch.optim.lr_scheduler import*
#继承了Dataset的类
class DogCat(data.Dataset):
def__init__(self, root, transform=None, train=True, test=False):
'''root表⽰⽤于训练的图⽚地址,前70%⽤于训练,后30%⽤于测试
'''
imgs =[os.path.join(root, img) for img in os.listdir(root)] #imgs是⼀个list,list中放(编号,图⽚地址)
st:#如果是test集
imgs =sorted(imgs, key=lambda x: int(x.split('.')[-2].split('/')[-1]))
else: #如果是train集
imgs =sorted(imgs, key=lambda x: int(x.split('.')[-2]))
imgs_num =len(imgs)
st:
self.imgs =imgs
else:
random.shuffle(imgs)
ain:
self.imgs =imgs[:int(0.7*imgs_num)]#self.imgs表⽰前百分之七⼗
else:
self.imgs =imgs[int(0.7*imgs_num):]#self.imgs表⽰除了前百分之七⼗
# 作为迭代器必须有的⽅法,可以⽤[]符号读取数据
def__getitem__(self, index):
img_path =self.imgs[index]
st:
label =int(self.imgs[index].split('.')[-2].split('/')[-1])
else:
label =1if'dog'in img_path.split('/')[-1] else0# 狗的label设为1,猫的设为0
data =Image.open(img_path)
data =ansform(data)
return data, label
def__len__(self):
def__len__(self):
return len(self.imgs)
# 对数据集训练集的处理
transform_train =transforms.Compose([
transforms.Resize((256, 256)), # 先调整图⽚⼤⼩⾄256x256
transforms.RandomCrop((224, 224)), # 再随机裁剪到224x224
transforms.RandomHorizontalFlip(), # 随机的图像⽔平翻转,通俗讲就是图像的左右对调
transforms.ToTensor(), #图⽚转换为Tensor
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.2225)) # 归⼀化,数值是⽤ImageNet给出的数值])
# 对数据集验证集的处理
transform_val =transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
])
device =torch.device('cuda'if torch.cuda.is_available() else'cpu') # 若能使⽤cuda,则使⽤cuda
trainset =DogCat('/mnt/ssd0/zhangwentao/train', transform=transform_train)
valset =DogCat('/mnt/ssd0/zhangwentao/train', transform=transform_val)
#继承了dataset dataset ⼀捆有多⼤数据顺序多线程输⼊,=0表⽰单线程trainloader =torch.utils.data.DataLoader(trainset, batch_size=20, shuffle=True, num_workers=0)
valloader =torch.utils.data.DataLoader(valset, batch_size=20, shuffle=False, num_workers=0)
#acc为准确率,该函数计算准确率
def get_acc(output, label):
total =output.shape[0]
_, pred_label =output.max(1)
num_correct =(pred_label ==label).sum().item()
return num_correct /total
#训练epoch次
def train(epoch):
scheduler.step() #按照Pytorch的定义是⽤来更新优化器的学习率的
train_acc =0.0#准确率
for batch_idx, (img, label) in enumerate(trainloader):
image =Variable(img.cuda())#放到gpu上
label =Variable(label.cuda())#放到ppu上
<_grad()#意思是把梯度置零,也就是把loss关于weight的导数变成0.
out =model(image) #投喂图⽚
loss =criterion(out, label)#利⽤交叉熵损失函数算出out和label的差别
loss.backward()#反向传播
optimizer.step()
train_acc =get_acc(out, label)#获得准确率
print("Epoch:%d [%d|%d] loss:%f acc:%f"%(epoch, batch_idx, len(trainloader), an(), train_acc)) #验证准确率
def val(epoch):
print("\nValidation Epoch: %d"%epoch)
model.eval()#进⼊推理模式
total =0
correct =0
_grad():
_grad():
for batch_idx, (img, label) in enumerate(valloader):
image =Variable(img.cuda())
label =Variable(label.cuda())
out =model(image)
_, predicted =torch.max(out.data, 1)
total +=image.size(0)
correct +=predicted.data.eq(label.data).cpu().sum()
print("Acc: %f "%((1.0*correct.numpy()) /total))
class Net(nn.Module):
''' 继承了nn.Module便于操作
pytorch的resnet18接⼝的最后⼀层fc层的输出维度是1000。这明显不符合猫狗⼤战数据集,
因为猫狗⼤战数据集是⼆分类的,所以最后⼀层fc输出的维度已经是2才对。
因此我们需要对resnet18进⾏最后⼀层的修改。
'''
def__init__(self, model):
super(Net, self).__init__()
# 取掉model的后1层
self.Linear_layer =nn.Linear(512, 2) # 加上⼀层参数修改好的全连接层
def forward(self, x):
x =snet_layer(x)
x =x.view(x.size(0), -1)
x =self.Linear_layer(x)
return x
if__name__ =='__main__':
model =Net(resnet18(pretrained=True))
model =(device)#转到gpu上运⾏
#model.parameters()为当前的⽹络模型的参数空间,lr为学习率,
optimizer =torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9, weight_decay=5e-4) # 设置训练细节 '''torch.optim是⼀个实现各种优化算法的包,优化器
优化器就是需要根据⽹络反向传播的梯度信息来更新⽹络的参数,以起到降低loss函数计算值的作⽤
'''
scheduler =StepLR(optimizer, step_size=3)
criterion =nn.CrossEntropyLoss()#交叉熵损失函数
for epoch in range(1):
train(epoch)
val(epoch)
#torch.save(model, 'modelcatdog.pth') # 保存模型
<("cpu")#转换回cpu
model.eval()#注意,必须进⼊推理模式。详细看pytorch官⽅⽂档
dummy_input =Variable(torch.randn(1, 3, 224, 224)) #设置⼊⼝的shape
#把模型转换为onnx模型,
dummy_input,
"", input_names=["input"],
opset_version=9)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论