第四次作业:猫狗大战挑战赛

一、题目

Kaggle 于2013年举办的猫狗大战比赛,判断一张输入图像是“猫”还是“狗”。该教程使用在 ImageNet 上预训练 的 VGG 网络进行测试。因为原网络的分类结果是1000类,所以这里进行迁移学习,对原网络进行 fine-tune (即固定前面若干层,作为特征提取器,只重新训练最后两层)。

题目详情:AI研习社:猫狗大战–经典图像分类题
本次作业的主要内容为:图像分类、迁移学习、VGG模型

二、思路及代码

注意:使用平台为Google Colab,具体使用方法较为简单,可自行网上搜索教程

1、引入相关包并判断是否存在GPU设备

import shutil
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())

2、下载数据集

方法一

# 数据集原始数据
! wget https://static.leiphone.com/cat_dog.rar
! apt-get install rar
! unrar x cat_dog.rar
# 训练集(两千张版本)
#! #wget http://fenggao-image.stor.sinaapp.com/dogscats.zip
#! #unzip dogscats.zip

方法二

前提:先将数据保存至Google云端硬盘

#挂载
from google.colab import drive
drive.mount('/content/drive')
!unzip "/content/drive/MyDrive/cat&dog/cat_dog.zip"

保证代码正确运行,稍微改变了下解压后目录
保证代码正确运行,稍微改变了下解压后目录

3、数据处理

#数据处理
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 = './cat_dog'

dsets = {x: datasets.ImageFolder(os.path.join(data_dir, x), vgg_format)for x in ['train', 'val', 'test']}

dset_sizes = {x: len(dsets[x]) for x in ['train', 'val', 'test']}
print(dset_sizes)#查看数据集大小

#定义loader
loader_train = torch.utils.data.DataLoader(dsets['train'], batch_size=100, shuffle=True, num_workers=10)
loader_valid = torch.utils.data.DataLoader(dsets['val'], batch_size=5, shuffle=False, num_workers=6)
loader_test = torch.utils.data.DataLoader(dsets['test'], batch_size=1, shuffle=False, num_workers=6)

4、创建 VGG Model

#创建模型
model_vgg = models.vgg16(pretrained=True)
#固定前15层参数
for param in model_vgg.parameters():
    param.requires_grad = False

5、修改最后一层,冻结前面层的参数

#改变16层
model_vgg.classifier._modules['6'] = nn.Linear(4096, 2)
model_vgg.classifier._modules['7'] = torch.nn.LogSoftmax(dim = 1)

model_vgg_new = model_vgg.to(device)

6、训练并验证全连接层

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

criterion = nn.NLLLoss()
# 学习率
lr = 0.001

# 随机梯度下降
#optimizer_vgg = torch.optim.SGD(model_vgg_new.classifier[6].parameters(),lr = lr)
optimizer_vgg = torch.optim.Adam(model_vgg_new.classifier[6].parameters(),lr = lr)

第二步:训练模型

#第二步:训练模型
def train_model(model,dataloader,size,epochs,optimizer=None):
    model.train()
    for epoch in range(epochs):
        running_loss = 0.0
        running_corrects = 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)
        epoch_loss = running_loss / size
        epoch_acc = running_corrects.data.item() / size
        print('Loss: {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))
    print("Train Finished!")

第三步:验证模型

#第三步:验证模型
def valid_model(model,dataloader,size):
    model.eval()
    running_loss = 0.0
    running_corrects = 0
    for inputs,classes in dataloader:
        inputs = inputs.to(device)
        classes = classes.to(device)
        outputs = model(inputs)
        loss = criterion(outputs,classes)           
        _,preds = torch.max(outputs.data,1)
        # statistics
        running_loss += loss.data.item()
        running_corrects += torch.sum(preds == classes.data)       
    epoch_loss = running_loss / size
    epoch_acc = running_corrects.data.item() / size
    torch.save(model, 'model_new_vgg.pt')
    print('Loss: {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))
    print("Test Finished!")

模型训练与验证

# 模型训练
train_model(model_vgg_new,loader_train,size=dset_sizes['train'],epochs=10,optimizer=optimizer_vgg)
# 模型验证
valid_model(model_vgg_new,loader_valid,size=dset_sizes['val'])

模型训练结果
模型验证结果

三、测试

result = {}
def test_model(model, dataloader, size):
    model.eval()
    result_index = 0
    #total_preds = []
    for inputs, classes in dataloader:
        inputs = inputs.to(device)
        outputs = model(inputs)
        _, preds = torch.max(outputs.data, 1)
        #total_preds.extend(preds)
        #'./cat_dog/test/catsOrDogs/1846.jpg', 1),
        key = dsets['test'].imgs[result_index][0].split('catsOrDogs/')[1].split('.')[0]
        result[key] = preds[0]
        result_index = 1 + result_index
    #保存结果文件
    with open("./result.csv", 'w') as f:
      for key in range(2000):
        f.write("{},{}\n".format(key,result[str(key)]))
test_model(torch.load('model_new_vgg.pt'),loader_test,size=dset_sizes['test'])

四、结果及心得

AI研习社提交结果

1、数据集结构

为保证dsets赋值语句直接包含test,遂将test文件夹下照片移至新建子文件中。

2、result处理结果集设置

因按数据处理顺序保存处理结果,会存在乱序现象,并直接导致提交结果评审得分大大降低,遂使用result重新保存结果集。具体设置方法在test_model定义中:

key = dsets['test'].imgs[result_index][0].split('catsOrDogs/')[1].split('.')[0]
        result[key] = preds[0]
        result_index = 1 + result_index

3、注意“二、3、”中loader参数设置

#定义loader
loader_train = torch.utils.data.DataLoader(dsets['train'], batch_size=100, shuffle=True, num_workers=10)
loader_valid = torch.utils.data.DataLoader(dsets['val'], batch_size=5, shuffle=False, num_workers=6)
loader_test = torch.utils.data.DataLoader(dsets['test'], batch_size=1, shuffle=False, num_workers=6)
  • loader_test中batch_size设置为1,否则len(result)将变成
  • dset_sizes[‘test’]/batch_size,别问为啥,被小bug恶心了好一会……
  • 调整batch_size和num_workers会得到不同正确率,时间充足可不断尝试,以得到更好正确率,因使用平台为Google Colab且数据集较大,故本次实验尝试次数有限~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值