Четвертая домашняя битва кошек и собак

алгоритм внешний интерфейс

Четвертая домашняя битва кошек и собак

запросить анализ

  • Создайте модель, обучите модель с помощью 25 000 помеченных изображений кошек и собак и, наконец, протестируйте ее на 125 000 изображений кошек и собак.
  • Конечная цель — сделать так, чтобы модель имела более высокий уровень правильного распознавания (ожидаемое значение: >=80%).
  • Модель должна использовать модель VGG
  • Количество протестированных и обученных изображений за это время невелико, если нет графического процессора, задачу можно выполнить, полагаясь на центральный процессор

Создавайте сеть шаг за шагом

1. Определите, есть ли устройство GPU

Цель этого шага — узнать, доступны ли в текущей среде устройства 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())

image.png

2. Загрузите набор данных для тестирования

Вот набор данных Джереми Ховарда, ссылка кажется мертвой

В наборе данных, предоставленном Джереми Ховардом, кошки и собаки размещены в разных папках.

Вот набор данных, предоставленный моим учителем, ссылка действительна

Вот инструкция по установке Colab

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

Не забудьте разархивировать

unzip dogscats.zip

image.png

В наборе данных, предоставленном моим учителем, есть папка Train для обучения и Vaild для тестирования. Две папки содержат две подпапки, собаки и кошки соответственно. Две подпапки содержат 900 изображений соответственно.

Если вы обучаете и тестируете модель в colab или в среде с недостаточной вычислительной мощностью, вы можете отдать приоритет папке, предоставленной моим учителем, а время обучения и размер набора данных тесно связаны.

Наблюдая за картинками в папке, можно обнаружить, что многие из картинок представляют собой не только чистых кошек и собак, но и некоторые другие элементы, такие как лица и т. д. Этот тип изображений может усилить обучающий эффект модели.Уменьшить неспособность модели распознавать изображения с мелкими или размытыми объектами.

cat.6.jpg

2. Предварительная обработка данных

Модель VGG предъявляет требования к размеру данных: изображение должно быть в формате 224x224x3.

image.png

Поэтому нам нужно предварительно обработать данные, чтобы наши картинки соответствовали требованиям модели VGG.

На этом этапе мы использовали пакетные наборы данных в torchvision, которые могут ускорить скорость загрузки изображений за счет чтения изображений через многопоточность и отправлять изображения в обучающую сеть в мини-пакетном режиме.Изображения подвергаются различной предварительной обработке. (формализация, кадрирование, перелистывание, джиттерин)

[Официальная документация для torchvision.transforms здесь](torchvision.transforms — Документация Torchvision 0.11.0 (pytorch.org))

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

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 数据一共有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)

image.png

# 显示图片的小程序

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])

image.png

3. Создайте модель VGG

torchvision собрал около 1,2 млн обучающих данных в imageNet В этой работе мы можем напрямую использовать предварительно обученную модель VGG, а также добавлять файлы jason классов imageNet1000.

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

image.png

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()])

image.png

4. Измените последний слой модели

В этом обучении нам нужно судить только о кошках и собаках, поэтому мы перепишем последний слой полной связи как nn.Linera(4096,2)

Здесь, чтобы заморозить параметры предыдущего слоя, можно установить required_grad=False, чтобы предыдущие веса не обновлялись автоматически.

print(model_vgg)

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)

print(model_vgg_new.classifier)

image.png

5. Обучите и протестируйте полностью связанный слой

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

损失函数 NLLLoss() 的 输入 是一个对数概率向量和一个目标标签. 
它不会为我们计算对数概率,适合最后一层是log_softmax()的网络. 
'''
criterion = nn.NLLLoss()

# 学习率
lr = 0.001

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

'''
第二步:训练模型
'''

def train_model(model,dataloader,size,epochs=1,optimizer=None):
    model.train()
    
    for epoch in range(epochs):
        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
        print('Loss: {:.4f} Acc: {:.4f}'.format(
                     epoch_loss, epoch_acc))
        
        
# 模型训练
train_model(model_vgg_new,loader_train,size=dset_sizes['train'], epochs=1, 
            optimizer=optimizer_vgg)

image.png

6. Визуализируйте результаты тестирования модели

Здесь мы используем субъективный анализ, который фактически выводит предсказанные результаты и соответствующие тестовые изображения, Существует в основном пять методов.

  1. Случайно посмотрите на некоторые картинки, которые правильно предсказаны

  2. Случайно посмотреть на некоторые ошибочно предсказанные картинки

  3. Предсказание верное, а картина с большой долей вероятности

  4. Ошибки предсказания, а картинки с большой вероятностью

  5. Наиболее неопределенные изображения, такие как изображения с прогнозируемой вероятностью, близкой к 0,5.


# 单次可视化显示的图片个数
n_view = 8
correct = np.where(predictions==all_classes)[0]
from numpy.random import random, permutation
idx = permutation(correct)[:n_view]
print('random correct idx: ', idx)
loader_correct = torch.utils.data.DataLoader([dsets['valid'][x] for x in idx],
                  batch_size = n_view,shuffle=True)
for data in loader_correct:
    inputs_cor,labels_cor = data
# Make a grid from batch
out = torchvision.utils.make_grid(inputs_cor)
imshow(out, title=[l.item() for l in labels_cor])

image.png

7. Примените модель к битве кошек и собак.

Здесь мы используем битву кошек и собак Исследовательского института ИИ.

Сначала загрузите набор данных

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

распаковать его

unrar x cat_dog.rar

делать предсказания

predictions, all_proba, all_classes = test_model(model_vgg_new,loader_test,size=dset_sizes['test'])

вывод CSV,Обязательно обратите внимание на порядок нарезки, я тут давно застрял

import csv
with open('./dogscats/1.csv','w',newline="")as f:
  writer = csv.writer(f)
  for index,cls in enumerate(predictions):
    path = datasets.ImageFolder(os.path.join(data_dir,'test'),vgg_format).imgs[index][0]
    l = path.split("/")
    img_name = l[-1]
    order = int(img_name.split(".")[0])
    writer.writerow([order,int(predictions[index])])

Не забудьте отсортировать его, чтобы он соответствовал требованиям формата данных.

Конечный результат

После теста картину можно пройти

image.png