在本实验中,我们将建一个模型来完成 Kaggle 中的猫狗大战竞赛题目。在这个比赛中,有25000张标记好的猫和狗的图片用做训练,有12500张图片用做测试。

文章目录

导入包并启用GPU导入数据数据集目录

数据预处理将训练集进行shuffle = True并分别load至对应的loader中对valid数据进行计数,并把第一个 batch 保存到 inputs_try,labels_try对数据进行打印预览

创建 VGG Model获取模型优化并训练模型使用最优模型测试AI研习社数据集

提交

导入包并启用GPU

import numpy as np

import matplotlib.pyplot as plt

import os

import torch

import torch.nn as nn

import torchvision

from torchvision import models,transforms,datasets

import time

import json

# 判断是否存在GPU设备

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

print('Using gpu: %s ' % torch.cuda.is_available())

导入数据

!wget http://fenggao-image.stor.sinaapp.com/dogscats.zip

!unzip dogscats.zip

!wget https://static.leiphone.com/cat_dog.rar

!unrar x /content/cat_dog.rar

第一个数据集为老师准备的数据集,因为这个代码需要在colab上跑,速度会相对较慢。因此,我们重新整理了数据,制作了新的数据集,训练集包含1800张图(猫的图片900张,狗的图片900张),测试集包含2000张图。 第二个为AI研习社的数据,数据量较大

数据集目录

test:最后通过训练好的模型来识别的测试图片train:用来训练模型的图片。val:文件夹下的图片有确定的标签,用来测试模型训练效果。

dogscats 数据集同理

数据预处理

datasets 是 torchvision 中的一个包,可以用做加载图像数据。它可以以多线程(multi-thread)的形式从硬盘中读取数据,使用 mini-batch 的形式,在网络训练中向 GPU 输送。在使用CNN处理图像时,需要进行预处理。图片将被整理成2242243的大小,同时还将进行归一化处理。

torchvision 支持对输入数据进行一些复杂的预处理/变换 (normalization, cropping, flipping, jittering 等)

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

vgg_format = transforms.Compose([

transforms.CenterCrop(224),

transforms.ToTensor(),

normalize,

])

data_dir = './dogscats'

dsets = {x: datasets.ImageFolder(os.path.join(data_dir, x), vgg_format)

for x in ['train', 'valid']}

dset_sizes = {x: len(dsets[x]) for x in ['train', 'valid']}

dset_classes = dsets['train'].classes

# 通过下面代码可以查看 dsets 的一些属性

print(dsets['train'].classes)

print(dsets['train'].class_to_idx)

print(dsets['train'].imgs[:5])

print('dset_sizes: ', dset_sizes)

classes 图像类别class_to_index 类别索引数据索引 {cat:0,dog:1}

将训练集进行shuffle = True并分别load至对应的loader中

loader_train = torch.utils.data.DataLoader(

dsets['train'], batch_size=64, shuffle=True, num_workers=6)

loader_valid = torch.utils.data.DataLoader(

dsets['valid'], batch_size=5, shuffle=False, num_workers=6)

对valid数据进行计数,并把第一个 batch 保存到 inputs_try,labels_try

'''

valid 数据一共有2000张图,每个batch是5张,因此,下面进行遍历一共会输出到 400

同时,把第一个 batch 保存到 inputs_try, labels_try,分别查看

'''

count = 1

for data in loader_valid:

print(count, end='\n')

if count == 1:

inputs_try,labels_try = data

count +=1

print(labels_try)

print(inputs_try.shape)

对数据进行打印预览

# 显示图片的小程序

def imshow(inp, title=None):

# Imshow for Tensor.

inp = inp.numpy().transpose((1, 2, 0))

mean = np.array([0.485, 0.456, 0.406])

std = np.array([0.229, 0.224, 0.225])

inp = np.clip(std * inp + mean, 0,1)

plt.imshow(inp)

if title is not None:

plt.title(title)

plt.pause(0.001) # pause a bit so that plots are updated

# 显示 labels_try 的5张图片,即valid里第一个batch的5张图片

out = torchvision.utils.make_grid(inputs_try)

imshow(out, title=[dset_classes[x] for x in labels_try])

创建 VGG Model

torchvision中集成了很多在 ImageNet (120万张训练数据) 上预训练好的通用的CNN模型,可以直接下载使用。

在本课程中,我们直接使用预训练好的 VGG 模型。同时,为了展示 VGG 模型对本数据的预测结果,还下载了 ImageNet 1000 个类的 JSON 文件。

在这部分代码中,对输入的5个图片利用VGG模型进行预测,同时,使用softmax对结果进行处理,随后展示了识别结果。可以看到,识别结果是比较非常准确的。

pretrained设置为True程序会自动下载已经训练好的参数。models.vgg16包含用于解决不同任务的模型定义,包括:图像分类,逐像素语义分割,对象检测,实例分割,人员检测和视频分类。

!wget https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json

model_vgg = models.vgg16(pretrained=True)

with open('./imagenet_class_index.json') as f:

class_dict = json.load(f)

dic_imagenet = [class_dict[str(i)][1] for i in range(len(class_dict))]

inputs_try , labels_try = inputs_try.to(device), labels_try.to(device)

model_vgg = model_vgg.to(device)

outputs_try = model_vgg(inputs_try)

print(outputs_try)

print(outputs_try.shape)

'''

可以看到结果为5行,1000列的数据,每一列代表对每一种目标识别的结果。

但是我也可以观察到,结果非常奇葩,有负数,有正数,

为了将VGG网络输出的结果转化为对每一类的预测概率,我们把结果输入到 Softmax 函数

'''

m_softm = nn.Softmax(dim=1)

probs = m_softm(outputs_try)

vals_try,pred_try = torch.max(probs,dim=1)

print( 'prob sum: ', torch.sum(probs,1))

print( 'vals_try: ', vals_try)

print( 'pred_try: ', pred_try)

print([dic_imagenet[i] for i in pred_try.data])

imshow(torchvision.utils.make_grid(inputs_try.data.cpu()),

title=[dset_classes[x] for x in labels_try.data.cpu()])

获取模型

我们的目标是使用预训练好的模型,并且只对全连接层的最后一层进行改写nn.Linear(4096, 2)使得最后输出的结果只有两个,即分辨猫与狗。为了在训练中冻结前面层的参数,需要设置 required_grad=False。这样,反向传播训练梯度时,前面层的权重就不会自动更新了。训练的时候只会更新最后一层的参数。

model_vgg_new = model_vgg;

for param in model_vgg_new.parameters():

param.requires_grad = False #冻结参数

'''

更改最后一层输出层

'''

model_vgg_new.classifier._modules['6'] = nn.Linear(4096, 2)

model_vgg_new.classifier._modules['7'] = torch.nn.LogSoftmax(dim = 1)

model_vgg_new = model_vgg_new.to(device)

'''

输出新的vgg模型

'''

print(model_vgg_new.classifier)

优化并训练模型

创建损失函数和优化器;训练模型与保存;测试模型。

'''

第一步:创建损失函数和优化器

损失函数 NLLLoss() 的 输入 是一个对数概率向量和一个目标标签.

它不会为我们计算对数概率,适合最后一层是log_softmax()的网络.

'''

criterion = nn.NLLLoss()

# 学习率

lr = 0.001

torch.optim 是实现各种优化算法的软件包,通过torch.optim构造一个优化器对象,该对象将保持当前状态并根据所计算的梯度来更新参数。这里使用Adam优化器,Adam在很多情况下算作默认工作性能比较优秀的优化器。根据预测的最好的情况通过torch.save()保存训练好的模型,后期对测试集进行测试时通过torch.load()加载模型。

# 这里使用Adam优化器

optimizer_vgg = torch.optim.Adam(model_vgg_new.classifier[6].parameters(),lr = lr)

'''

第二步:训练模型并保存

model: 训练的模型

dataloader: 训练集

size: 训练集大小

epochs: 训练次数

optimizer: 优化器

'''

def train_model(model,dataloader,size,epochs=1,optimizer=None):

model.train() #用于模型训练

for epoch in range(epochs):

epoch_acc_max = 0

running_loss = 0.0

running_corrects = 0

count = 0

for inputs,classes in dataloader:

inputs = inputs.to(device)

classes = classes.to(device)

outputs = model(inputs) #参数前向传播

loss = criterion(outputs,classes)

optimizer = optimizer

optimizer.zero_grad() #优化器梯度初始化

loss.backward() #梯度反向传播

optimizer.step()

_,preds = torch.max(outputs.data,1) #得到预测结果

# statistics

running_loss += loss.data.item()

running_corrects += torch.sum(preds == classes.data)

count += len(inputs)

print('Training: No. ', count, ' process ... total: ', size)

epoch_loss = running_loss / size

epoch_acc = running_corrects.data.item() / size

if epoch_acc > epoch_acc_max:

epoch_acc_max = epoch_acc

torch.save(model, 'model_best.pth') #保存最好模型

print('Loss: {:.4f} Acc: {:.4f}'.format(

epoch_loss, epoch_acc))

# 模型训练

train_model(model_vgg_new, loader_train,size = dset_sizes['train'],

epochs = 5, optimizer=optimizer_vgg)

一共进行了5轮,loss和准确率分别是

Loss: 0.0067 Acc: 0.8356Loss: 0.0035 Acc: 0.9456Loss: 0.0026 Acc: 0.9611Loss: 0.0023 Acc: 0.9589Loss: 0.0021 Acc: 0.9644

使用最优模型测试AI研习社数据集

dsets = datasets.ImageFolder('/content/cat_dog', vgg_format)

final = {} #结果数组

loader_test = torch.utils.data.DataLoader(dsets, batch_size=1, shuffle=False, num_workers=0)

model_vgg_new = torch.load("/content/model_best.pth")

def test(model,dataloader,size):

model.eval() #参数固定

cnt = 0 #count

for inputs,_ in dataloader:

if cnt < size:

inputs = inputs.to(device)

outputs = model(inputs)

_,preds = torch.max(outputs.data,1) #预测值最大化

key = dsets.imgs[cnt][0].split("/")[-1].split('.')[0] #对目录项进行分割

final[key] = preds[0]

cnt += 1

else:

break;

test(model_vgg_new,loader_test,size=2000)

''''

写表格

''''

with open("/content/test.csv",'a+') as f:

for key in range(2000):

f.write("{},{}\n".format(key,final[str(key)]))

提交

代码地址:https://github.com/boom-10/deep_study_se/blob/main/dog%26%26cat.ipynb

相关阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: