实战3. 利用Pytorch预写好ResNet-18预测电视剧《辛普森一家》中的人物——图像分类

实战3. 利用ResNet-18预测电视剧《辛普森一家》中的人物

你将训练一个神经网络来预测电视剧《辛普森一家》中的人物。

您将获得一个训练和测试数据集。您将需要在训练数据上训练神经网络并在测试数据上获得预测。

加载数据

下载数据档案并解压该数据集。

python 复制代码
! pip install wldhx.yadisk-direct
! curl -L $(yadisk-direct https://disk.yandex.com/d/Ggl9017wNIN0vg) -o simpsons.zip

注意! Yandex云盘对每天从链接同时下载的数量施加了一些限制。因此,上面单元格中的代码可能会产生错误。在这种情况下,您需要取消注释并从下面的单元格中运行代码(其中,数据是从备用链接下载的):

python 复制代码
#! pip install wldhx.yadisk-direct
#! curl -L $(yadisk-direct https://disk.yandex.ru/d/MweozIqon2ybsQ) -o simpsons.zip

接下来,解压:

python 复制代码
! unzip -qq simpsons.zip

导入必要的库:

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

from PIL import Image

import torch
import torch.nn as nn
import torch.optim as optim

import torchvision
from torchvision import datasets, models, transforms

让我们定义在将图像输入神经网络之前要执行的转换。您可以按照自己的意愿改变这些转换。

请注意,如果您要使用预先训练的神经网络(vgg、resnet 等),则转换应该与预先训练该神经网络时使用的转换相同。在 pytorch 文档中可以找到给定网络使用哪些转换以及如何在代码中使用它们。

如果您从头开始训练自己的神经网络,则可以自行选择转换。

python 复制代码
resnet_transforms = transforms.Compose([
        transforms.Resize(256), # 每幅图像的尺寸将缩小到 256*256
        transforms.CenterCrop(224), # 图片的中心部分将被剪掉,尺寸为 224*224
        transforms.ToTensor(), # 图像从python数组转换为torch.Tensor格式
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 图像像素值归一化
    ])

# 特定预训练网络的转换更容易像这样获得
# resnet_transforms = models.ResNet18_Weights.IMAGENET1K_V1.transforms()

让我们从数据中创建数据集。请注意,对于测试数据,您不知道答案:在 ./simpsons_data/test 文件夹中没有带有类名的子文件夹,只有一个包含所有图像的文件夹。您的任务是使用您知道答案的训练数据来训练神经网络,使用训练后的神经网络获得测试数据的预测,并将其作为答案提交。

python 复制代码
train_data = datasets.ImageFolder('./simpsons_data/train', transform=resnet_transforms)
test_data = datasets.ImageFolder('./simpsons_data/test', transform=resnet_transforms)

我们来得到类别编号和类别名称的对应关系:

python 复制代码
class_to_idx = train_data.class_to_idx
class_to_idx

输出:

{'abraham_grampa_simpson': 0,

'agnes_skinner': 1,

'apu_nahasapeemapetilon': 2,

'barney_gumble': 3,

'bart_simpson': 4,

'carl_carlson': 5,

'charles_montgomery_burns': 6,

'chief_wiggum': 7,

'cletus_spuckler': 8,

'comic_book_guy': 9,

'disco_stu': 10,

'edna_krabappel': 11,

'fat_tony': 12,

'gil': 13,

'groundskeeper_willie': 14,

'homer_simpson': 15,

'kent_brockman': 16,

'krusty_the_clown': 17,

'lenny_leonard': 18,

'lionel_hutz': 19,

'lisa_simpson': 20,

'maggie_simpson': 21,

'marge_simpson': 22,

'martin_prince': 23,

'mayor_quimby': 24,

'milhouse_van_houten': 25,

'miss_hoover': 26,

'moe_szyslak': 27,

'ned_flanders': 28,

'nelson_muntz': 29,

'otto_mann': 30,

'patty_bouvier': 31,

'principal_skinner': 32,

'professor_john_frink': 33,

'rainier_wolfcastle': 34,

'ralph_wiggum': 35,

'selma_bouvier': 36,

'sideshow_bob': 37,

'sideshow_mel': 38,

'snake_jailbird': 39,

'troy_mcclure': 40,

'waylon_smithers': 41}

我们将训练样本分为两部分:训练和验证。在训练部分,像往常一样,我们将训练神经网络,在验证部分我们将测试网络。

python 复制代码
# 我们将把 80% 的图片纳入训练样本
train_size = int(len(train_data) * 0.8)
# 进行验证 - 剩余 20%
val_size = len(train_data) - train_size

train_data, val_data = torch.utils.data.random_split(train_data, [train_size, val_size])

让我们为三部分数据创建三个数据加载器:

python 复制代码
train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_data, batch_size=64, shuffle=False)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=64, shuffle=False)

让我们看一下训练集中的几张图片,以了解我们正在处理的内容。

python 复制代码
for batch in test_loader:
    # 一批图片和一批图片答案
    images, labels = batch
    break
python 复制代码
def show_images(images, labels):
    f, axes= plt.subplots(1, 10, figsize=(30,5))

    for i, axis in enumerate(axes):
        # 将图像从张量转换为numpy
        img = images[i].numpy()
        # 将图像转换为尺寸(长度、宽度、颜色通道)
        img = np.transpose(img, (1, 2, 0))

        axes[i].imshow(img)
        axes[i].set_title(labels[i].numpy())

    plt.show()

图像将在转换之后绘制,因此如果在转换过程中进行了规范化,则图像的颜色可能不太自然。不要害怕=)

python 复制代码
show_images(images, labels)

输出:

模型建立与训练

您的任务是根据训练和验证数据训练神经网络,并获得测试数据的预测。要建立和训练神经网络,您可以而且应该使用以前的课程和实战的材料。

关于如何提高速度的想法:

  • 尝试从头开始训练你的神经网络,就像我们在第四课实战2中所做的那样。尝试改变网络架构和各种超参数(层数、层中的过滤器等)以获得最佳验证分数;
  • 尝试采用预先训练的神经网络(例如 resnet-18),并在我们的数据上重新训练它,就像我们在第五课中所做的那样。注意转换:它们必须与您正在训练的架构相匹配。尝试冻结不同数量的层并观察它如何影响结果。
  • 尝试将数据增强应用于训练样本。您可以在 Habr 上阅读有关数据增强的内容。 pytorch 中增强的示例可以在文档中找到
    请注意,增强仅适用于训练集。它不应应用于验证和测试样本。因此,您需要创建两个不同的转换管道:一个用于训练部分,一个用于验证和测试部分。

在网络训练过程中,要注意验证速度。验证指标的值是一个指导方针,可让您了解网络在测试样本上的行为方式。但请注意,测试和验证样本的结果可能有所不同。

检查 GPU 是否可用(如果不可用,请在笔记本电脑设置中启用 GPU):

python 复制代码
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

建立神经网络:

python 复制代码
# 你的代码:建立并训练一个神经网络
# resnet-18 模型
model = models.resnet18(pretrained=True)
# model.eval()
# model.eval可查看该神经网络结构

设置 evaluate 函数用于评估模型性能,train 函数用于训练模型并在每个训练周期结束后进行验证。

python 复制代码
def evaluate(model, dataloader, loss_fn):

    losses = []

    num_correct = 0
    num_elements = 0

    for i, batch in enumerate(dataloader):

        # 获取当前批次
        X_batch, y_batch = batch
        num_elements += len(y_batch)

        # 此行禁用梯度计算
        with torch.no_grad():
            # 获取批量图像的网络响应
            logits = model(X_batch.to(device))

            # 计算当前批次的损失
            loss = loss_fn(logits, y_batch.to(device))
            losses.append(loss.item())

            # 计算网络响应作为每幅图像的类别编号
            y_pred = torch.argmax(logits, dim=1)

            # 计算当前批次中正确的网络响应数量
            num_correct += torch.sum(y_pred.cpu() == y_batch)

    # 计算最终正确答案的百分比
    accuracy = num_correct / num_elements

    return accuracy.numpy(), np.mean(losses)

def train(model, loss_fn, optimizer, n_epoch=3):

    # 网络训练周期
    for epoch in range(n_epoch):

        print("Epoch:", epoch+1)

        model.train(True)

        running_losses = []
        running_accuracies = []
        for i, batch in enumerate(train_loader):
            # 获取当前批次
            X_batch, y_batch = batch

            # 前向传递(获取对一批图像的响应)
            logits = model(X_batch.to(device))

            # 计算网络给出的答案和批次的正确答案的损失
            loss = loss_fn(logits, y_batch.to(device))
            running_losses.append(loss.item())

            loss.backward() # backpropagation(梯度计算)
            optimizer.step() # 更新网络权重
            optimizer.zero_grad() # 重置权重

            # 计算当前训练批次的准确率
            model_answers = torch.argmax(logits, dim=1)
            train_accuracy = torch.sum(y_batch == model_answers.cpu()) / len(y_batch)
            running_accuracies.append(train_accuracy)

            # 记录结果
            if (i+1) % 50 == 0:
                print("Average train loss and accuracy over the last 50 iterations:",
                      np.mean(running_losses), np.mean(running_accuracies), end='\n')

        # 每个时期之后,我们都会得到验证样本的质量指标
        model.train(False)

        val_accuracy, val_loss = evaluate(model, val_loader, loss_fn=loss_fn)
        print("Epoch {}/{}: val loss and accuracy:".format(epoch+1, n_epoch,),
                      val_loss, val_accuracy, end='\n')

    return model
python 复制代码
# 再次声明模型
model = model.to(device)

# 选择损失函数
loss_fn = torch.nn.CrossEntropyLoss()

# 选择优化算法和学习率。
# 你可以尝试不同的 learning_rate 值
learning_rate = 1e-3
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# 让我们开始训练模型
# 参数 n_epoch 可以变化
model = train(model, loss_fn, optimizer, n_epoch=3)

输出:

获取样本

使用训练好的模型对测试数据集进行预测,并将预测结果保存到一个 .npy 文件中。具体步骤包括:定义一个用于获取预测标签的函数,使用该函数对测试数据进行预测,将预测的索引转换为对应的类别名称,最后将结果保存为 submission_hw05.npy 文件。

python 复制代码
def get_predictions(model, dataloader):

    predicted_labels = []
    model.eval()
    predicted_labels = []

    for i, batch in enumerate(dataloader):

        # 这就是我们获取当前批次的方法
        X_batch, _ = batch

        with torch.no_grad():
            logits = model(X_batch.to(device))
            y_pred = torch.argmax(logits, dim=1)
            predicted_labels.append(y_pred)

    predicted_labels = torch.cat(predicted_labels)
    return predicted_labels

# model --- 包含你的模型的变量。
predicted_labels = get_predictions(model, test_loader)
idx_to_class = {y:x for x, y in class_to_idx.items()}
predicted_labels = [idx_to_class[x] for x in predicted_labels.data.cpu().numpy()]

np.save('submission_hw05.npy', predicted_labels, allow_pickle=True)
print('The answer has been saved to file. `submission_hw05.npy`')
相关推荐
救救孩子把20 分钟前
集成开发环境革新:IntelliJ IDEA与Cursor AI的智能演进
java·人工智能·intellij-idea
jndingxin25 分钟前
OpenCV图像拼接(6)图像拼接模块的用于创建权重图函数createWeightMap()
人工智能·opencv·计算机视觉
杨超越luckly27 分钟前
Python应用指南:利用高德地图API获取POI数据(关键词版)
大数据·python·数据挖掘·数据分析·html
九亿AI算法优化工作室&1 小时前
SA模拟退火算法优化高斯回归回归预测matlab代码
人工智能·python·算法·随机森林·matlab·数据挖掘·模拟退火算法
Blossom.1181 小时前
基于Python的机器学习入门指南
开发语言·人工智能·经验分享·python·其他·机器学习·个人开发
郝YH是人间理想2 小时前
Python面向对象
开发语言·python·面向对象
藍海琴泉2 小时前
蓝桥杯算法精讲:二分查找实战与变种解析
python·算法
默 语2 小时前
10分钟打造专属AI助手!ToDesk云电脑/顺网云/海马云操作DeepSeek哪家强?
人工智能·电脑·todesk
Donvink4 小时前
【Dive Into Stable Diffusion v3.5】2:Stable Diffusion v3.5原理介绍
人工智能·深度学习·语言模型·stable diffusion·aigc·transformer
宇灵梦4 小时前
大模型金融企业场景落地应用
人工智能