实战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 分钟前
隧道调频广播覆盖的实现路径:隧道无线广播技术赋能行车安全升级,隧道汽车广播收音系统助力隧道安全管理升级
人工智能
Huanzhi_Lin24 分钟前
python源码打包为可执行的exe文件
python
CareyWYR26 分钟前
每周AI论文速递(250421-250425)
人工智能
声声codeGrandMaster37 分钟前
django之账号管理功能
数据库·后端·python·django
追逐☞1 小时前
机器学习(10)——神经网络
人工智能·神经网络·机器学习
winner88811 小时前
对抗学习:机器学习里的 “零和博弈”,如何实现 “双赢”?
人工智能·机器学习·gan·对抗学习
Elastic 中国社区官方博客1 小时前
使用 LangGraph 和 Elasticsearch 构建强大的 RAG 工作流
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
娃娃略1 小时前
【AI模型学习】双流网络——更强大的网络设计
网络·人工智能·pytorch·python·神经网络·学习
福尔摩东1 小时前
从零到精通:2025年最全大模型学习资源
人工智能·github
青橘MATLAB学习1 小时前
深度学习中的预训练与微调:从基础概念到实战应用全解析
人工智能·深度学习·微调·迁移学习·预训练·梯度消失·模型复用