首页 > 其他分享 >使用AMD GPU进行图像分类的ResNet模型

使用AMD GPU进行图像分类的ResNet模型

时间:2024-11-07 16:48:59浏览次数:6  
标签:loss torch batch AMD ResNet epoch train test GPU

ResNet for image classification using AMD GPUs — ROCm Blogs

2024年4月9日,作者:Logan Grado。

在这篇博客中,我们演示了如何使用ROCm在AMD GPU上训练一个简单的ResNet模型来进行CIFAR10数据集的图像分类。在AMD GPU上训练ResNet模型非常简单,仅需安装ROCm和适当的PyTorch库,无需额外的工作。

介绍

ResNet 模型最初由Kaiming He等人在 2015 年发表于Deep Residual Learning for Image Recognition 中,主要用于图像分类。该论文的关键贡献是引入了残差连接(residual connections),它允许训练比以往网络更深的网络(参见下图)。ResNet 模型被用于多种情境中,如图像分类、目标检测等。

png

残差连接示意图,来自原始论文。残差连接(右)绕过计算块。

先决条件

要跟随本博客的内容,您需要以下条件:

运行本文代码

本文代码有两种运行方式。首先,您可以使用Docker(推荐),或者您可以构建自己的Python环境(参见附录中的在主机上运行)。

在 Docker 中运行

使用 Docker 是构建所需环境的最简单和最可靠的方法。

  • 确保你已经安装了 Docker。如果没有,请参阅安装说明

  • 确保您在主机上安装了 amdgpu-dkms(随 ROCm 一起提供),以便从 Docker 内部访问 GPU。请参阅ROCm Docker 说明

  • 克隆仓库,并进入博客目录

    git clone [email protected]:ROCm/rocm-blogs.git
    cd rocm-blogs/blogs/artificial-intelligence/resnet
    
  • 构建并启动容器。有关构建过程的详细信息,请参阅 dockerfile。这将启动一个 jupyter lab 服务器。

    cd docker
    docker compose build
    docker compose up
    
  • 在浏览器中导航到 http://localhost:8888,以笔记本格式打开文件 resnet_blog.py(right click -> open with -> notebook)

    注意

    注意:此笔记本是一个JupyText 配对笔记本,采用 py-percent 格式

在 CIFAR10 数据集上训练 ResNet 18

下面,我们将逐步讲解训练代码。

导入

首先,导入所需的包

import random
import datetime

import torch
import torchvision
from torchvision.transforms import v2 as transforms
from datasets import load_dataset
import matplotlib.pyplot as plt

数据集

任务中,我们将使用 CIFAR10 ,数据集,该数据集可以从 huggingface下载。CIFAR10数据集由60,000张32x32的图像组成,分为10个类别。

我们定义一个函数来获取训练和测试的dataloader。在这个函数中,我们将 (1) 下载数据集,(2) 设置数据格式为torch,(3) 构建训练和测试数据加载器。

def get_dataloaders(batch_size=256):
    """
    返回cifar10数据集的测试/训练数据加载器
    """
    # 下载数据集,并设置格式为torch
    dataset = load_dataset("cifar10")
    dataset.set_format("torch")

    # 构建训练/测试加载器
    train_loader = torch.utils.data.DataLoader(dataset["train"], shuffle=True, batch_size=batch_size)
    test_loader = torch.utils.data.DataLoader(dataset["test"], batch_size=batch_size)

    return train_loader, test_loader

数据变换

该数据集中的图像像素编码格式为 uint8,因此我们需要将其转换为 float32 并进行归一化。以下函数构造了一个组合变换,用于准备训练数据。

在下面的函数中,我们构造了一个组合的 torchvision transform,具体执行以下操作:

  • 重新排列通道维度,使得我们的一批图像是“通道优先”的格式,这是 pytorch 所要求的

  • 转换为 float32 类型

  • 将值缩放到 [0,1] 范围

  • 将值归一化到均值 0,标准差 1

def get_transform():
    """
    构建并返回一个变换链,将加载的图像转换为正确的格式/数据类型,并进行归一化
    """
    # CIFAR10 数据集的均值和标准差
    stats = ((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))

    transform = transforms.Compose(
        [
            # 该数据集是通道最后格式 (B, H, W, C),需要将其重新排列为通道优先格式 (B, C, H, W) transforms.Lambda(lambda x: x.permute(0, 3, 1, 2)),
            # 转换为 float32 类型
            transforms.ToDtype(torch.float32),
            # 除以 255 将 uint8 转换为 [0,1] 范围
            transforms.Lambda(lambda x: x / 255),
            # 归一化
            transforms.Normalize(*stats, inplace=True),
        ]
    )
    return transform

构建模型、损失函数和优化器

接下来,我们需要构建在训练过程中使用的模型、损失函数以及优化器。

  • 模型: 我们将使用`torchvision`中的  ResNet18, 并将`num_classes`设置为10,以匹配CIFAR10数据集。`ResNet18`是较小规模的ResNet模型之一(由18个卷积层组成),适合进行较简单的任务,如CIFAR10分类。

  • 损失函数: 交叉熵损失, 标准的分类问题损失函数

  • 优化器: Adam 优化器

def build_model():
    """
    构建模型、损失函数和优化器
    """
    # ResNet18, 具有10个类别
    model = torchvision.models.resnet18(num_classes=10)

    # 标准的交叉熵损失
    loss_fn = torch.nn.CrossEntropyLoss()

    # Adam优化器
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=1e-4)

    return model, loss_fn, optimizer

训练循环 

最后,我们将使用 PyTorch 构建一个简单的训练循环。在这里,我们将训练模型经过预定数量的 epochs。在每个 epoch 中,我们对整个训练集进行一次完整的遍历,并计算训练损失。然后,我们对测试集进行一次完整的遍历,计算测试损失和准确率。

def train_model(model, loss_fn, optimizer, train_loader, test_loader, transform, num_epochs):
    """
    根据预定的 epoch 数量进行模型训练
    """
    # 声明训练设备
    print(f"Number of GPUs: {torch.cuda.device_count()}")
    print([torch.cuda.get_device_name(i) for i in range(torch.cuda.device_count())])
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    t0 = datetime.datetime.now()
    model.to(device)
    model.train()

    accuracy = []
    # 主训练循环
    for epoch in range(num_epochs):
        print(f"Epoch {epoch+1}/{num_epochs}")
        t0_epoch_train = datetime.datetime.now()

        # 迭代训练数据集
        train_losses, n_examples = [], 0
        for batch in train_loader:
            batch = {k: v.to(device) for k, v in batch.items()}

            optimizer.zero_grad()

            preds = model(transform(batch["img"]))

            loss = loss_fn(preds, batch["label"])
            loss.backward()
            optimizer.step()

            train_losses.append(loss)
            n_examples += batch["label"].shape[0]
        train_loss = torch.stack(train_losses).mean().item()
        t_epoch_train = datetime.datetime.now() - t0_epoch_train

        # 执行评估
        with torch.no_grad():
            t0_epoch_test = datetime.datetime.now()
            test_losses, n_test_examples, n_test_correct = [], 0, 0
            for batch in test_loader:
                batch = {k: v.to(device) for k, v in batch.items()}

                preds = model(transform(batch["img"]))

                loss = loss_fn(preds, batch["label"])

                test_losses.append(loss)
                n_test_examples += batch["img"].shape[0]
                n_test_correct += (batch["label"] == preds.argmax(axis=1)).sum()

            test_loss = torch.stack(test_losses).mean().item()
            test_accuracy = n_test_correct / n_test_examples
            t_epoch_test = datetime.datetime.now() - t0_epoch_test
            accuracy.append(test_accuracy.cpu())

        # 打印指标
        print(f"  Epoch time: {t_epoch_train+t_epoch_test}")
        print(f"  Examples/second (train): {n_examples/t_epoch_train.total_seconds():0.4g}")
        print(f"  Examples/second (test): {n_test_examples/t_epoch_test.total_seconds():0.4g}")

        print(f"  Train loss: {train_loss:0.4g}")
        print(f"  Test loss: {test_loss:0.4g}")
        print(f"  Test accuracy: {test_accuracy*100:0.4g}%")

    total_time = datetime.datetime.now() - t0
    print(f"Total training time: {total_time}")
    return accuracy

训练模型Train the Model

最后,我们可以把所有组件组合起来放进主方法中。在这里,我们将:

  • 设置随机种子以确保可重复性

  • 构建所有组件(模型、数据加载器等)

  • 调用我们的训练方法

seed = 0
random.seed(seed)
torch.manual_seed(seed)

model, loss, optimizer = build_model()
train_loader, test_loader = get_dataloaders()
transform = get_transform()

test_accuracy = train_model(model, loss, optimizer, train_loader, test_loader, transform, num_epochs=8)
    Epoch 1/8
      Epoch time: 0:00:15.129099
      Examples/second (train): 3639
      Examples/second (test): 7204
      Train loss: 1.796
      Test loss: 1.409
      Test accuracy: 48.88%
    ...
    Epoch 8/8
      Epoch time: 0:00:07.136725
      Examples/second (train): 8182
      Examples/second (test): 9748
      Train loss: 0.6939
      Test loss: 0.7904
      Test accuracy: 72.87%
    Total training time: 0:00:57.931011

接下来,我们画出训练过程中准确率的变化情况。

fig,ax = plt.subplots()
ax.plot(test_accuracy)
ax.set_xlabel("epoch")
ax.set_ylabel("accuracy")
plt.show()

最后,我们可以绘制一些预测图像来查看我们的结果。

label_dict = {0: 'airplane',1: 'automobile',2: 'bird',3: 'cat',4: 'deer',5: 'dog',6: 'frog',7: 'horse',8: 'ship',9: 'truck'}

# 绘制前5张图片
N = 5
device='cuda'
for batch in test_loader:
    batch = {k: v.to(device) for k, v in batch.items()}
    preds = model(transform(batch["img"])).argmax(axis=1)
    labels = batch['label'].cpu()

    fig,ax = plt.subplots(1,N,tight_layout=True)
    for i in range(N):
        ax[i].imshow(batch['img'][i].cpu())
        ax[i].set_xticks([])
        ax[i].set_yticks([])
        ax[i].set_xlabel(f"Label: {label_dict[labels[i].item()]}\nPred: {label_dict[preds[i].item()]}")
    
    break

png

总结

在这篇博客中,我们展示了如何使用AMD GPU在CIFAR10数据集上训练ResNet图像分类器,并在不到一分钟的时间内实现了73%的准确率!所有这些都可以在搭载ROCm的AMD GPU上无缝运行。我们可以通过采用一些技术进一步提高性能,例如学习率调度器、数据增强和更多的训练轮数,这些技术将留给读者自己完成。

参考文献

附录

在主机上运行

如果您不想使用 Docker,也可以直接在您的机器上运行这篇博客 - 虽然这需要多一点工作。

  •  先决条件:

    • 安装ROCm 5.7.x

    • 确保您已经安装了 Python 3.10

    • 安装 PDM - 在这里用于创建可重复的 Python 环境

  • 在博客的根目录下创建 Python 虚拟环境:

    pdm sync
    
  • 启动笔记本

    pdm run jupyter-lab
    

导航到 https://localhost:8888 并运行博客 

标签:loss,torch,batch,AMD,ResNet,epoch,train,test,GPU
From: https://blog.csdn.net/eidolon_foot/article/details/143580916

相关文章

  • CUDA开始的GPU编程 - 第四章:C++封装GPU上的数组
    第四章:C++封装GPU上的数组std::vector的秘密:第二模板参数**你知道吗?**std::vector作为模板类,其实有两个模板参数:std::vector<T,AllocatorT>那为什么我们平时只用了std::vector呢?因为第二个参数默认是std::allocator。也就是std::vector等价于std::vector<T,s......
  • GPU 环境搭建指南:如何在裸机、Docker、K8s 等环境中使用 GPU
    本文主要分享在不同环境,例如裸机、Docker和Kubernetes等环境中如何使用GPU。跳转阅读原文:GPU环境搭建指南:如何在裸机、Docker、K8s等环境中使用GPU1.概述仅以比较常见的NVIDIAGPU举例,系统为Linux,对于其他厂家的GPU设备理论上流程都是一样的。省流:对于裸......
  • **AI的三大支柱:神经网络、大数据与GPU计算的崛起之路**
      每周跟踪AI热点新闻动向和震撼发展想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行!订阅:https://......
  • 基于卷积神经网络的柑桔病害识别与防治系统,resnet50,mobilenet模型【pytorch框架+pytho
     更多目标检测和图像分类识别项目可看我主页其他文章功能演示:柑橘病害识别与防治系统,卷积神经网络,resnet50,mobilenet【pytorch框架,python源码】_哔哩哔哩_bilibili(一)简介基于卷积神经网络的柑桔病害识别与防治系是在pytorch框架下实现的,这是一个完整的项目,包括代码,数据集,......
  • [使用整理-1] bamdst:统计覆盖度和测序深度
    BAMDSTBamdst是一个轻量级工具,用于统计bam文件中目标区域的测序深度、覆盖度。必须使用排序后的bam文件,bed文件和输出目录必须优先指定。1.下载安装gitclonehttps://github.com/shiquan/bamdst.gitcdbamdst/make或者使用conda:condainstallxdgene::bamdst......
  • cuda、cudnn、zlib 深度学习GPU必配三件套(Ubuntu)
    跨大版本不推荐,到处是坑、坑、坑~。tensorrt10、cuda12、cudnn9是目前最新的大版本,但是对于一般的老显卡(1050等),太新可能提醒一些错误(主要是tensorrt太新导致的)。为了不折腾,使用如下版本:tensorrt8.6.1、cuda11.8、cudnn8.9.7默认已经安装了英伟达显卡的最新版本驱动。系统Ubuntu22......
  • Ollama简介,以及中文使用指南和AMD图形显卡驱动下载
    Ollama是一个开源的大型语言模型(LLM)服务工具,它旨在简化在本地运行大语言模型的过程,降低使用大语言模型的门槛。Ollama使得开发者、研究人员和爱好者能够在本地环境快速实验、管理和部署最新的大语言模型,包括但不限于如Qwen2、Llama3、Phi3、Gemma2等开源的大型语言模型。Oll......
  • 基于卷积神经网络的大豆病虫害识别与防治系统,resnet50,mobilenet模型【pytorch框架+pyt
     更多目标检测和图像分类识别项目可看我主页其他文章功能演示:大豆病虫害识别与防治系统,卷积神经网络,resnet50,mobilenet【pytorch框架,python源码】_哔哩哔哩_bilibili(一)简介基于卷积神经网络的大豆病虫害识别与防治系统是在pytorch框架下实现的,这是一个完整的项目,包括代码,......
  • 基于AMD显卡安装Pytorch(小白攻略)
    安装的时候看了很多博客,踩了一些雷,现在把成功下载的流程汇总下来。假设这个时候已经安装好了ubuntu,我安装的是ubuntu22.04.安装rocmLinux®DriversforAMDRadeon™andRadeonPRO™Graphics可以点击上面这个链接,点击ubuntux8664-bit.我选的是带rocm的版本复制这......
  • 深入解析Amdahl定律与Gustafson定律:并行计算的加速之道
    如果你觉得这篇文章对你有帮助,请不要吝惜你的“关注”、“点赞”、“评价”、“收藏”,你的支持永远是我前进的动力~~~个人收藏的技术大会分享PDF文档,欢迎点击下载查看!!!本文将探讨并行计算中的两个重要定律——Amdahl定律和Gustafson定律。通过分析这两个定律的原理、区别及实......