[Классификация изображений] Реальный бой — использование DenseNet для выявления облысения (pytorch)

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

содержание

Резюме

Импорт библиотеки, используемой проектом

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

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

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

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

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

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

полный код


Резюме

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

Сегодня мы используем DenseNet для классификации лысых голов, я разместил набор данных на Baidu Netdisk, адрес: ссылка:disk.baidu.com/is/177ET и B_1…Код извлечения: 47fo. Этот набор данных может беспокоить большинство программистов.

Пример набора данных показан ниже.

Это все лысые, их общая черта: они все мужчины, почему женщины не лысые? 

Импорт библиотеки, используемой проектом

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
import torchvision.datasets as datasets
from torch.autograd import Variable
from torchvision.models import densenet121

 

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

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

# 设置全局参数
modellr = 1e-4
BATCH_SIZE = 32
EPOCHS = 5
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])
])

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

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

В обучающем наборе 16 000 картинок, из них более 3000 лысых, а в проверочном наборе более 20 000 картинок, из которых лысых 470. Число слишком отличается, поэтому я случайным образом удалил часть. Затем напишите код для чтения данных.

dataset_train = datasets.ImageFolder('Dataset/Train', transform)
dataset_test = datasets.ImageFolder('Dataset/Validation',transform_test)
# 读取数据
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)

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


Используя перекрестную энтропию в качестве потерь, для модели используетсяdennet121, и рекомендуется использовать предварительно обученную модель.В процессе отладки я могу использовать предварительно обученную модель, чтобы быстро получить конвергентную модель.Используйте предварительно обученную модель. обученной модели, чтобы установить pretrained в True. Измените полное соединение последнего слоя, установите категорию 2 и поместите модель в DEVICE. Оптимизатор выбирает Адама.

# 实例化模型并且移动到GPU
criterion = nn.CrossEntropyLoss()
model_ft = densenet121(pretrained=True)
num_ftrs = model_ft.classifier.in_features
model_ft.classifier = nn.Linear(num_ftrs, 2)
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

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

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

Этапы, которые должен пройти тренировочный процесс:

Первый шаг: распространение ввода вперед, после операции получается вывод вывода, код: вывод = модель (данные)

Шаг 2: Введите выходные данные в функцию потерь, рассчитайте значение потерь (которое является скаляром), код: потеря = критерий (выход, цель)

Шаг 3: Обратно распространите градиент на каждый параметр, код: loss.backward()

Шаг 4: Инициализируйте значение параметра grad равным 0, код: optimizer.zero_grad()

Шаг 5: Обновите веса, код: optimizer.step()

Процесс проверки в основном похож на процесс обучения.

 

# 定义训练过程

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

После завершения можно запускать, и результаты следующие:

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

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

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

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

Третий шаг — загрузить модель и поместить модель в 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=('Bald','NoBald')
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='Dataset/Test/Bald/'
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()]))

Результаты приведены ниже:

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

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


classes=('Bald','NoBald')
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('Dataset/Test',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], classes[pred.data.item()]))
    index += 1

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

полный код

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

import torchvision.datasets as datasets
from torch.autograd import Variable
from torchvision.models import densenet121

# 设置全局参数
modellr = 1e-4
BATCH_SIZE = 32
EPOCHS = 5
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('Dataset/Train', transform)
dataset_test = datasets.ImageFolder('Dataset/Validation',transform_test)
# 读取数据
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)

# 实例化模型并且移动到GPU
criterion = nn.CrossEntropyLoss()
model_ft = densenet121(pretrained=True)
num_ftrs = model_ft.classifier.in_features
model_ft.classifier = nn.Linear(num_ftrs, 2)
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


# 定义训练过程

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

DenseNet Image Classification.zip-Deep Learning Document Class Resources-CSDN Download