基于Python的图像分类模型训练与部署实践

今天 3阅读

在当前人工智能技术飞速发展的背景下,图像分类作为计算机视觉领域的一个核心任务,已经成为许多实际应用的基础。本文将通过一个完整的实战案例,介绍如何使用 Python 和深度学习框架(如 PyTorch)构建、训练并部署一个图像分类模型。整个流程包括数据准备、模型构建、训练、评估以及模型导出和部署。

我们将以经典的 CIFAR-10 数据集为例,使用 ResNet 架构进行图像分类任务。最终我们会将训练好的模型转换为 ONNX 格式,并使用 ONNX Runtime 进行推理测试。


环境准备

首先,我们需要安装必要的库:

pip install torch torchvision onnx onnxruntime

我们使用的工具如下:

PyTorch:用于模型构建和训练。ONNX:用于模型格式转换。ONNX Runtime:用于部署模型进行推理。

数据准备与预处理

我们将使用 PyTorch 提供的 torchvision.datasets.CIFAR10 数据集,包含 10 类彩色图像(每张大小为 32x32)。

import torchfrom torchvision import datasets, transformsfrom torch.utils.data import DataLoader# 定义数据变换transform = transforms.Compose([    transforms.ToTensor(),    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# 加载训练集和测试集train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)test_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

模型构建:ResNet-18

我们使用 PyTorch 提供的预定义 ResNet-18 模型,并修改最后一层以适配 CIFAR-10 的类别数量。

import torch.nn as nnimport torchvision.models as modelsdef get_model():    model = models.resnet18(pretrained=False)    model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)    model.maxpool = nn.Identity()  # 修改 maxpool 层以适应 CIFAR-10 图像尺寸    model.fc = nn.Linear(512, 10)  # 修改输出层为10类    return modelmodel = get_model()device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model.to(device)

模型训练

我们使用交叉熵损失函数和 Adam 优化器进行训练。

import torch.optim as optimcriterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练循环for epoch in range(5):  # 只训练5个epoch作为示例    model.train()    running_loss = 0.0    for images, labels in train_loader:        images, labels = images.to(device), labels.to(device)        optimizer.zero_grad()        outputs = model(images)        loss = criterion(outputs, labels)        loss.backward()        optimizer.step()        running_loss += loss.item()    print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}")# 测试准确率model.eval()correct = 0total = 0with torch.no_grad():    for images, labels in test_loader:        images, labels = images.to(device), labels.to(device)        outputs = model(images)        _, predicted = torch.max(outputs.data, 1)        total += labels.size(0)        correct += (predicted == labels).sum().item()print(f"Test Accuracy: {100 * correct / total:.2f}%")

运行结果可能如下:

Epoch 1, Loss: 1.23Epoch 2, Loss: 0.91...Test Accuracy: 78.5%

模型保存与导出为 ONNX

为了便于部署,我们将训练好的模型导出为 ONNX 格式。

dummy_input = torch.randn(1, 3, 32, 32, device=device)input_names = ["input"]output_names = ["output"]torch.onnx.export(    model,    dummy_input,    "resnet_cifar10.onnx",    export_params=True,  # 存储训练参数    opset_version=11,  # ONNX 算子集版本    do_constant_folding=True,  # 优化常量    input_names=input_names,    output_names=output_names,    dynamic_axes={        'input': {0: 'batch_size'},        'output': {0: 'batch_size'}    })print("Model has been converted to ONNX")

使用 ONNX Runtime 进行推理

我们可以使用 ONNX Runtime 来加载并运行 ONNX 模型。

import numpy as npimport onnxruntime as ort# 加载 ONNX 模型ort_session = ort.InferenceSession("resnet_cifar10.onnx")# 获取测试集中的一张图片images, labels = next(iter(test_loader))img = images[0].unsqueeze(0).cpu().numpy()  # 转换为 numpy array# 推理outputs = ort_session.run(    None,    {'input': img})# 获取预测结果predicted_class = np.argmax(outputs[0], axis=1)print(f"Predicted class: {predicted_class[0]}, Ground truth: {labels[0]}")

模型部署与性能优化建议

在生产环境中部署模型时,可以考虑以下几点:

量化压缩:使用 ONNX 或 PyTorch 自带的量化工具减少模型大小。多线程推理:利用 ONNX Runtime 的多线程支持提高吞吐量。GPU加速:配置 ONNX Runtime 使用 CUDA 加速推理过程。服务化部署:结合 Flask 或 FastAPI 封装成 REST API 提供图像识别服务。

总结

本文完整地演示了从图像分类模型的构建、训练、评估到模型导出与部署的全过程。通过 PyTorch 我们能够快速实现深度学习模型的开发,而借助 ONNX 与 ONNX Runtime,我们可以方便地将模型部署到不同平台和设备上,实现跨语言、跨系统的推理能力。

未来的工作可以扩展至更复杂的网络结构、更大的数据集,或引入迁移学习提升准确率。同时,也可以探索模型蒸馏、剪枝等方法来优化模型效率,以适应边缘计算场景的需求。


附录:完整代码汇总

import torchfrom torchvision import datasets, transformsfrom torch.utils.data import DataLoaderimport torchvision.models as modelsimport torch.nn as nnimport torch.optim as optimimport numpy as npimport onnxruntime as ort# 数据预处理transform = transforms.Compose([    transforms.ToTensor(),    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)test_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)# 构建模型def get_model():    model = models.resnet18(pretrained=False)    model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)    model.maxpool = nn.Identity()    model.fc = nn.Linear(512, 10)    return modelmodel = get_model()device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model.to(device)# 训练模型criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), lr=0.001)for epoch in range(5):    model.train()    running_loss = 0.0    for images, labels in train_loader:        images, labels = images.to(device), labels.to(device)        optimizer.zero_grad()        outputs = model(images)        loss = criterion(outputs, labels)        loss.backward()        optimizer.step()        running_loss += loss.item()    print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}")# 测试模型model.eval()correct = 0total = 0with torch.no_grad():    for images, labels in test_loader:        images, labels = images.to(device), labels.to(device)        outputs = model(images)        _, predicted = torch.max(outputs.data, 1)        total += labels.size(0)        correct += (predicted == labels).sum().item()print(f"Test Accuracy: {100 * correct / total:.2f}%")# 导出ONNX模型dummy_input = torch.randn(1, 3, 32, 32, device=device)torch.onnx.export(    model,    dummy_input,    "resnet_cifar10.onnx",    export_params=True,    opset_version=11,    do_constant_folding=True,    input_names=["input"],    output_names=["output"],    dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}})print("Model has been converted to ONNX")# ONNX推理测试ort_session = ort.InferenceSession("resnet_cifar10.onnx")images, labels = next(iter(test_loader))img = images[0].unsqueeze(0).cpu().numpy()outputs = ort_session.run(None, {'input': img})predicted_class = np.argmax(outputs[0], axis=1)print(f"Predicted class: {predicted_class[0]}, Ground truth: {labels[0]}")

如果你有特定的技术方向(比如图像分割、自然语言处理等),我也可以为你定制类似的文章内容。

免责声明:本文来自网站作者,不代表CIUIC的观点和立场,本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。客服邮箱:ciuic@ciuic.com

目录[+]

您是本站第5156名访客 今日有16篇新文章

微信号复制成功

打开微信,点击右上角"+"号,添加朋友,粘贴微信号,搜索即可!