实战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`')
相关推荐
科技小花1 小时前
全球化深水区,数据治理成为企业出海 “核心竞争力”
大数据·数据库·人工智能·数据治理·数据中台·全球化
X56612 小时前
如何在 Laravel 中正确保存嵌套动态表单数据(主服务与子服务)
jvm·数据库·python
zhuiyisuifeng2 小时前
2026前瞻:GPTimage2镜像官网或将颠覆视觉创作
人工智能·gpt
徐健峰2 小时前
GPT-image-2 热门玩法实战(一):AI 看手相 — 一张手掌照片生成专业手相分析图
人工智能·gpt
weixin_370976352 小时前
AI的终极赛跑:进入AGI,还是泡沫破灭?
大数据·人工智能·agi
Slow菜鸟2 小时前
AI学习篇(五) | awesome-design-md 使用说明
人工智能·学习
ZhengEnCi2 小时前
03ab-PyTorch安装教程 📚
python
冬奇Lab3 小时前
RAG 系列(五):Embedding 模型——语义理解的核心
人工智能·llm·aigc
深小乐3 小时前
AI 周刊【2026.04.27-05.03】:Anthropic 9000亿美元估值、英伟达死磕智能体、中央重磅定调AI
人工智能
码点滴3 小时前
什么时候用 DeepSeek V4,而不是 GPT-5/Claude/Gemini?
人工智能·gpt·架构·大模型·deepseek