[Классификация изображений] Actual Combat — использование GoogLeNet для идентификации аниме

искусственный интеллект

содержание

Резюме

Сделать набор данных

Импортируйте необходимые библиотеки

Установить глобальные параметры

предварительная обработка изображений

читать данные

Настроить модель

Настройка обучения и проверки

контрольная работа


Резюме

Дайте вам аниме картинку, не подскажете из какого она аниме? Сегодня мы делаем именно это с GoogLeNet. Я выбрал следующие аниме: «Священное дерево Циньлин», «Пожирающее звездное небо» и «Цинь Шиминюэ». Примерная картина выглядит следующим образом:

Священное дерево Циньлин

Цинь Ши Миньюэ

Поглотить звездное небо

Как видно из приведенного выше примера, между разными стилями аниме все еще есть большие различия.Давайте поговорим о том, как я реализую классификацию анимации.

Сделать набор данных

Чтобы создать набор данных, вам нужно извлечь изображения из анимации. Чтобы извлечь изображения, вам нужно использовать инструмент ffmpeg. Для конкретной установки и использования, пожалуйста, обратитесь к:Установите ffmpeg в Windows и используйте ffmpeg для извлечения изображений из видео.

Затем мы используем python, вызываем ffmeg для реализации логики пакетного извлечения аниме-видео, создаем две новые папки на диске D, одну папку с именем qlss, в этой папке хранятся аниме-видео, и одна папка — imags, которая используется для хранения добыча картина. Код в Python выглядит следующим образом:

import os
# 创建三个列表用来存储视频文件以及视频地址
file_list = []
file_list_path=[]
filelist = []
# 源文件目录
dir_path = 'D:\\qlss'
#cmd命令存入str字符串
str = 'ffmpeg ' + '-i {} -ss 00:00:30  -f image2 -vf fps=1/5 -qscale:v 2 ../imags/img_{}%05d.jpg'
filenameList=os.listdir(dir_path)
print(filenameList)
for j in range(len(filenameList)):
    filepath=os.path.join(dir_path,filenameList[j])
    str_cmd = str.format(filepath, filenameList[j].split('.')[0])
    print(str_cmd)
    os.popen(str_cmd)

Идея приведенного выше кода: пройтись по видеофайлу, использовать Python для выполнения команды ffmpeg в cmd для извлечения изображения.

Новый проект

Создайте новый проект классификации изображений, поместите набор данных в данные и настройте метод чтения данных в папке набора данных.На этот раз я не использую метод чтения по умолчанию, который слишком прост и бессмысленен. Затем создайте новый train.py и test.py.

Создайте новый файл train.py в корневом каталоге проекта, а затем напишите в нем обучающий код.

Импортируйте необходимые библиотеки

На этот раз я выбрал модель inception_v3.

import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
from dataset.dataset import SeedlingData
from torch.autograd import Variable
from torchvision.models import inception_v3

Установить глобальные параметры

Установите BatchSize, скорость обучения и эпохи, чтобы определить, существует ли среда cuda, если не установлено значение cpu.

# 设置全局参数
modellr = 1e-4
BATCH_SIZE = 32
EPOCHS = 10
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

предварительная обработка изображений

При выполнении изображения и обработки преобразование набора данных поезда и преобразование набора проверки выполняются отдельно.В дополнение к изменению размера и нормализации обработки изображения поезда вы также можете установить улучшения изображения, такие как вращение, случайное стирание, и т. д., проверочный набор не должен улучшать изображение и не делать улучшения вслепую, необоснованные методы улучшения могут привести к негативным последствиям или даже к потере неконвергенции. Примечание. Размер входных данных модели inception_v3 составляет 3 × 299 × 299.

transform = transforms.Compose([
    transforms.Resize((299, 299)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

])
transform_test = transforms.Compose([
    transforms.Resize((299, 299)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

читать данные

Разархивируйте набор данных и поместите его в папку данных, как показано на рисунке:

Затем мы создаем новые __init__.py и dataset.py в папке набора данных и пишем следующий код в папке dataset.py:

Расскажите об основной логике кода.

Первым шагом является создание словаря, определение идентификатора, соответствующего категории, и замена категории числом.

Второй шаг — написать метод получения пути к изображению в __init__. В тестовом наборе есть только один слой путей для непосредственного чтения, а обучающий набор - это папка категории в папке поезда.Сначала получается категория, а затем получается конкретный путь к изображению. Затем используйте метод разделения набора данных в sklearn, чтобы разделить набор для обучения и набор для проверки в соответствии с соотношением 7:3.

Третий шаг определяется в методе __getitem__, и определяется метод чтения одной картинки и категории.Из-за 32-битной глубины 32 в изображении я изменил при чтении изображения.

# coding:utf8
import os
from PIL import Image
from torch.utils import data
from torchvision import transforms as T
from sklearn.model_selection import train_test_split

Labels={'吞噬星空': 0, '秦岭神树': 1, '秦时明月': 2}
class SeedlingData (data.Dataset):

    def __init__(self, root, transforms=None, train=True, test=False):
        """
        主要目标: 获取所有图片的地址,并根据训练,验证,测试划分数据
        """
        self.test = test
        self.transforms = transforms

        if self.test:
            imgs = [os.path.join(root, img) for img in os.listdir(root)]
            self.imgs = imgs
        else:
            imgs_labels = [os.path.join(root, img) for img in os.listdir(root)]
            imgs = []
            for imglable in imgs_labels:
                for imgname in os.listdir(imglable):
                    imgpath = os.path.join(imglable, imgname)
                    imgs.append(imgpath)
            trainval_files, val_files = train_test_split(imgs, test_size=0.3, random_state=42)
            if train:
                self.imgs = trainval_files
            else:
                self.imgs = val_files

    def __getitem__(self, index):
        """
        一次返回一张图片的数据
        """
        img_path = self.imgs[index]
        img_path=img_path.replace("\\",'/')
        if self.test:
            label = -1
        else:
            labelname = img_path.split('/')[-2]
            label = Labels[labelname]
        data = Image.open(img_path).convert('RGB')
        data = self.transforms(data)
        return data, label

    def __len__(self):
        return len(self.imgs)

Затем мы вызываем SeedlingData в train.py для чтения данных, не забудьте импортировать только что написанный dataset.py (из dataset.dataset import SeedlingData)

dataset_train = SeedlingData('data/train', transforms=transform, train=True)
dataset_test = SeedlingData("data/train", transforms=transform_test, train=False)
# 读取数据
print(dataset_train.imgs)

# 导入数据
train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=False)

Настроить модель


В качестве потерь используйте CrossEntropyLoss, в модели используется inception_v3, а также используется предобучающая модель. Измените полносвязный слой, установите категорию последнего слоя на 3 и поместите модель в DEVICE. Оптимизатор выбирает Адама.

# 实例化模型并且移动到GPU
criterion = nn.CrossEntropyLoss()
model_ft = inception_v3(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 3)
model_ft.to(DEVICE)
# 选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(model_ft.parameters(), lr=modellr)


def adjust_learning_rate(optimizer, epoch):
    """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
    modellrnew = modellr * (0.1 ** (epoch // 50))
    print("lr:", modellrnew)
    for param_group in optimizer.param_groups:
        param_group['lr'] = modellrnew

Настройка обучения и проверки

Модель inception_v3 более ранняя, и выходные данные модели имеют два параметра, которые следует здесь отметить.

 output,hid = model(data)

# 定义训练过程

def train(model, device, train_loader, optimizer, epoch):
    model.train()
    sum_loss = 0
    total_num = len(train_loader.dataset)
    print(total_num, len(train_loader))
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = Variable(data).to(device), Variable(target).to(device)
        output,hid = 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:
            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()
    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')

Выполнив приведенный выше код, вы можете тренироваться.Три анимации совершенно разные, поэтому очень хорошие результаты получаются очень быстро. 

контрольная работа

Я представляю два часто используемых метода тестирования. Первый общий, вручную загружая набор данных, а затем делая прогнозы. Конкретные операции заключаются в следующем:

Каталог, в котором хранится тестовый набор, выглядит следующим образом:

Первый шаг - определить категории. Порядок этой категории соответствует порядку категорий во время обучения. Не меняйте порядок! ! ! !

Второй шаг – определение преобразований. Преобразования совпадают с преобразованиями проверочного набора. Не улучшайте данные.

Третий шаг — загрузить модель и поместить модель в DEVICE,

Четвертый шаг - прочитать изображение и предсказать категорию изображения.Обратите внимание, что изображение библиотеки PIL используется для чтения изображения. Не используйте cv2, преобразования не поддерживаются.

import torch.utils.data.distributed
import torchvision.transforms as transforms
from PIL import Image
from torch.autograd import Variable
import os
# classes = ('Black-grass', 'Charlock', 'Cleavers', 'Common Chickweed',
#            'Common wheat','Fat Hen', 'Loose Silky-bent',
#            'Maize','Scentless Mayweed','Shepherds Purse','Small-flowered Cranesbill','Sugar beet')
classes=('吞噬星空','秦岭神树','秦时明月')
transform_test = transforms.Compose([
         transforms.Resize((299, 299)),
        transforms.ToTensor(),
        transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = torch.load("model.pth")
model.eval()
model.to(DEVICE)

path='data/test/'
testList=os.listdir(path)
for file in testList:
        img=Image.open(path+file)
        img=transform_test(img)
        img.unsqueeze_(0)
        img = Variable(img).to(DEVICE)
        out=model(img)
        # Predict
        _, pred = torch.max(out.data, 1)
        print('Image Name:{},predict:{}'.format(file,classes[pred.data.item()]))

Я решил использовать набор Священного дерева Циньлин в качестве тестового набора, и текущий результат:

Второй использует пользовательский набор данных для чтения изображений.

import torch.utils.data.distributed
import torchvision.transforms as transforms
from dataset.dataset import SeedlingData
from torch.autograd import Variable

# classes = ('Black-grass', 'Charlock', 'Cleavers', 'Common Chickweed',
#            'Common wheat','Fat Hen', 'Loose Silky-bent',
#            'Maize','Scentless Mayweed','Shepherds Purse','Small-flowered Cranesbill','Sugar beet')
classes=('吞噬星空','秦岭神树','秦时明月')
transform_test = transforms.Compose([
    transforms.Resize((299, 299)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = torch.load("model.pth")
model.eval()
model.to(DEVICE)

dataset_test =SeedlingData('data/test/', transform_test,test=True)
print(len(dataset_test))
# 对应文件夹的label

for index in range(len(dataset_test)):
    item = dataset_test[index]
    img, label = item
    img.unsqueeze_(0)
    data = Variable(img).to(DEVICE)
    output = model(data)
    _, pred = torch.max(output.data, 1)
    print('Image Name:{},predict:{}'.format(dataset_test.imgs[index], classes[pred.data.item()]))
    index += 1

 

Найдите «AI Xiaohao» в официальном аккаунте, подпишитесь и ответьте на «GooLeNet Actual Combat», чтобы получить исходный код, модель и набор данных.