[Классификация изображений] Фактический бой — использование EfficientNetV2 для классификации изображений (Pytorch)

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

содержание

Резюме

Новый проект

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

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

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

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

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

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

проверять

Полный код:


Резюме

За последние несколько дней я изучил EfficientNetV2, перевел статью и воспроизвел код статьи.

Перевод диссертации:[Классификация изображений] EfficientNetV2: быстрее, меньше, сильнее — Бумажный перевод — Ищу программиста

Код для воспроизведения:[Классификация изображений] Воспроизведение EfficientNetV2 с помощью простого для понимания кода — отличный выбор для входа (pytorch) — требуется программист

Если вы хотите узнать об EfficientNetV2, вы можете прочитать статью выше, В этой статье основное внимание уделяется тому, как использовать EfficientNetV2 для реализации классификации изображений. Функция Loss использует CrossEntropyLoss, которая может легко реализовать бинарную классификацию и мультиклассификацию, изменив полное соединение последнего слоя. Набор данных использует классический набор данных войны кошек и собак для реализации двух классификаций.

Адрес набора данных: ссылка:disk.Baidu.com/Yes/1 Кроме того, HV PO идет на V…
Код извлечения: 3ch6

Новый проект

Создайте новый проект классификации изображений, создайте новую модель папки в последующем каталоге проекта для хранения кода модели EfficientNetV2, создайте новый EfficientNetV2.py и поместите[Классификация изображений] Воспроизведение EfficientNetV2 с помощью простого для понимания кода — отличный выбор для входа (pytorch) — требуется программистСкопируйте в него воспроизведенный код, а затем создайте новый пустой файл __init__.py в папке с моделью Структура каталогов модели следующая:

 

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

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

 

import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.optim
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torch.autograd import Variable
from model.EfficientNetv2 import efficientnetv2_s

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


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

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

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

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

# 数据预处理
 
transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
 
])
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

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

Используйте способ Pytorch по умолчанию для чтения данных. Каталог данных выглядит следующим образом:

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

# 读取数据
dataset_train = datasets.ImageFolder('data/train', transform)
print(dataset_train.imgs)
# 对应文件夹的label
print(dataset_train.class_to_idx)
dataset_test = datasets.ImageFolder('data/val', transform_test)
# 对应文件夹的label
print(dataset_test.class_to_idx)
 
# 导入数据
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 в качестве потерь, модель принимает Effectivenetv2_s, поскольку для Pytorch нет предварительно обученной модели, мы можем обучаться только с нуля. Измените полное соединение последнего слоя, установите категорию 2 и поместите модель в DEVICE. Оптимизатор выбирает Адама.

# 实例化模型并且移动到GPU
criterion = nn.CrossEntropyLoss()
model = efficientnetv2_s()
num_ftrs = model.classifier.in_features
model.classifier = nn.Linear(num_ftrs, 2)
model.to(DEVICE)
# 选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(model.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

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

# 定义训练过程

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 = 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) % 50 == 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, DEVICE, train_loader, optimizer, epoch)
    val(model, DEVICE, test_loader)
torch.save(model, 'model.pth')

После ввода вышеуказанного кода вы можете начать тренировку, нажмите «Выполнить», чтобы начать тренировку, как показано ниже:

проверять


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

Первый шаг - определить категории. Порядок этой категории соответствует порядку категорий во время обучения. Не меняйте порядок! ! ! ! Когда мы тренируемся, категория кошек равна 0, а категория собак — 1, поэтому я определяю классы как (кошка, собака).

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

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

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

import torch.utils.data.distributed
import torchvision.transforms as transforms
 
from torch.autograd import Variable
import os
from PIL import Image
 
classes = ('cat', 'dog')
 
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    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()]))
 
 



результат операции:

На самом деле, при чтении данных datasets.ImageFolder также можно использовать с умом.Далее мы будем использовать datasets.ImageFolder для прогнозирования изображений. Измените путь к тестовому набору данных, добавьте слой файлов вне тестовой папки и назовите его набором данных, как показано на следующем рисунке:

Затем измените способ чтения изображения. код показывает, как показано ниже:

import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torch.autograd import Variable
 
classes = ('cat', 'dog')
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    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 = datasets.ImageFolder('data/datatest', transform_test)
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][0], classes[pred.data.item()]))
    index += 1
 

Полный код:

train.py

import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.optim
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torch.autograd import Variable
from model.EfficientNetv2 import efficientnetv2_s
# 设置全局参数
modellr = 1e-4
BATCH_SIZE = 32
EPOCHS = 50
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 数据预处理

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

])
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
# 读取数据
dataset_train = datasets.ImageFolder('data/train', transform)
print(dataset_train.imgs)
# 对应文件夹的label
print(dataset_train.class_to_idx)
dataset_test = datasets.ImageFolder('data/val', transform_test)
# 对应文件夹的label
print(dataset_test.class_to_idx)

# 导入数据
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)


# 实例化模型并且移动到GPU
criterion = nn.CrossEntropyLoss()
model = efficientnetv2_s()
num_ftrs = model.classifier.in_features
model.classifier = nn.Linear(num_ftrs, 2)
model.to(DEVICE)
# 选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(model.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


# 定义训练过程

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 = 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) % 50 == 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, DEVICE, train_loader, optimizer, epoch)
    val(model, DEVICE, test_loader)
torch.save(model, 'model.pth')

test1.py

 
import torch.utils.data.distributed
import torchvision.transforms as transforms
 
from torch.autograd import Variable
import os
from PIL import Image
 
classes = ('cat', 'dog')
 
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    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()]))
 
 

test2.py

import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torch.autograd import Variable
 
classes = ('cat', 'dog')
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    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 = datasets.ImageFolder('data/datatest', transform_test)
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][0], classes[pred.data.item()]))
    index += 1