掘金 人工智能 07月10日 10:38
深度学习模型在C++平台的部署
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了将深度学习模型从Python环境部署到C++生产环境的方法。文章首先概述了深度学习模型在实际生产中的重要性,然后详细介绍了将PyTorch或TensorFlow等框架训练好的模型转换为ONNX格式,并在C++环境中加载和运行的步骤。通过一个手写数字识别的CNN模型示例,展示了完整的模型训练、导出、C++部署和推理过程,为开发者提供了实用的参考。

🧐 深度学习模型部署的重要性:随着深度学习在生产环境中的广泛应用,将Python训练好的模型部署到C++平台变得至关重要,以保证模型的稳定性和高效性。

💡 模型转换的关键环节:将Python环境下训练好的模型保存为.onnx格式是实现C++部署的关键步骤,.onnx格式提供了跨框架的互操作性。

⚙️ C++环境的部署流程:在C++环境中,需要安装Microsoft.ML.OnnxRuntime程序包,加载.onnx模型文件,并编写代码完成模型推理功能。

🔢 手写数字识别示例:文章提供了一个手写数字识别的CNN模型示例,演示了从Python模型的训练、导出,到C++环境下的加载和推理的全过程。

🖼️ 图像数据预处理:在C++部署过程中,需要对输入数据进行预处理,例如将图像数据转换为模型所需的格式,以便模型能够正确进行推理。

一、概述

  深度学习模型能够在各种生产场景中发挥重要的作用,而深度学习模型往往在Python环境下完成训练,因而训练好的模型如何在生产环境下实现稳定可靠的部署,便是一个重要内容。C++开发平台广泛存在于各种复杂的生产环境,随着业务效能需求的不断提高,充分运用深度学习技术的优势显得尤为重要。本文介绍如何实现将深度学习模型部署在C++平台上。

二、步骤

  s1. Python环境中安装深度学习框架(如PyTorch、TensorFlow等);

  s2. Python环境中设计并训练深度学习模型;

  s3. 将训练好的模型保存为.onnx格式的模型文件;

  s4. C++环境中安装Microsoft.ML.OnnxRuntime程序包;
  (Visual Studio 2022中可通过项目->管理NuGet程序包完成快捷安装)

  s5. C++环境中加载模型文件,完成功能开发。

三、示例

  在Python环境下设计并训练一个关于手写数字识别的卷积神经网络(CNN)模型,将模型导出为ONNX格式的文件,然后在C++环境下完成对模型的部署和推理。

1. Python训练和导出

import torchimport torch.nn as nnimport torch.optim as optimfrom torchvision import datasets, transformsfrom torch.functional import F# 定义简单的CNN模型class SimpleCNN(nn.Module):    def __init__(self):        super(SimpleCNN, self).__init__()        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1)        self.pool = nn.MaxPool2d(2, 2)        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)        self.fc1 = nn.Linear(32 * 7 * 7, 128)        self.fc2 = nn.Linear(128, 10)    def forward(self, x):        x = self.pool(F.relu(self.conv1(x)))        x = self.pool(F.relu(self.conv2(x)))        x = x.view(-1, 32 * 7 * 7)        x = F.relu(self.fc1(x))        x = self.fc2(x)        return x# 数据预处理transform = transforms.Compose([    transforms.ToTensor(),    transforms.Normalize((0.1307,), (0.3081,))])# 加载训练数据train_dataset = datasets.MNIST('data', train=True, download=True, transform=transform)train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)# 初始化模型、损失函数和优化器model = SimpleCNN()criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练模型def train(model, train_loader, criterion, optimizer, epochs=5):    model.train()    for epoch in range(epochs):        running_loss = 0.0        for batch_idx, (data, target) in enumerate(train_loader):            optimizer.zero_grad()            output = model(data)            loss = criterion(output, target)            loss.backward()            optimizer.step()            running_loss += loss.item()        print(f'Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}')# 训练模型train(model, train_loader, criterion, optimizer)# 导出为ONNX格式dummy_input = torch.randn(1, 1, 28, 28)torch.onnx.export(    model,    dummy_input,    "mnist_model.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("模型已成功导出为mnist_model.onnx")

2. C++ 部署和推理

#include <iostream>#include <vector>#include <opencv2/opencv.hpp>#include <onnxruntime_cxx_api.h>int main() {    // 初始化环境    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "MNIST");    Ort::SessionOptions session_options;    session_options.SetIntraOpNumThreads(1);    session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);    // 加载模型    std::wstring model_path = L"mnist_model.onnx";    Ort::Session session(env, model_path.c_str(), session_options);    // 准备输入    std::vector<int64_t> input_shape = { 1, 1, 28, 28 };    size_t input_tensor_size = 28 * 28;    std::vector<float> input_tensor_values(input_tensor_size);        // 读取测试图片    cv::Mat test_image = cv::imread("test.jpg", cv::IMREAD_GRAYSCALE);             // 将Mat数据复制到vector中    for (int i = 0; i < test_image.rows; ++i) {        for (int j = 0; j < test_image.cols; ++j) {            input_tensor_values[i * test_image.cols + j] = static_cast<float>(test_image.at<uchar>(i, j)); // 注意:uchar是unsigned char的缩写,表示无符号字符,通常用于存储灰度值        }    }     // 创建输入张量    auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);    Ort::Value input_tensor = Ort::Value::CreateTensor<float>(        memory_info, input_tensor_values.data(), input_tensor_size, input_shape.data(), 4);    // 设置输入输出名称    std::vector<const char*> input_names;    std::vector<const char*> output_names;    input_names.push_back(session.GetInputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get());    output_names.push_back(session.GetOutputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get());    // 运行推理    auto output_tensors = session.Run(        Ort::RunOptions{ nullptr },        input_names.data(),        &input_tensor,        1,        output_names.data(),        1);    // 获取输出结果    float* output = output_tensors[0].GetTensorMutableData<float>();    std::vector<float> results(output, output + 10);    // 找到预测的数字    int predicted_digit = 0;    float max_probability = results[0];    for (int i = 1; i < 10; i++) {        if (results[i] > max_probability) {            max_probability = results[i];            predicted_digit = i;        }    }    std::cout << "预测结果: " << predicted_digit << std::endl;    std::cout << "置信度分布:" << std::endl;    for (int i = 0; i < 10; i++) {        std::cout << "数字 " << i << ": " << results[i] << std::endl;    }    return 0;}

测试图片:

程序运行:



End.

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

深度学习 C++ 模型部署 ONNX 手写数字识别
相关文章