C# ONNX使用入门教程

背景

有新入坑的老哥不太了解C# onnx 运行的机理,我这边详细介绍一下,之前直接放官方的样例有点草率了。

准备[python环境]

1、要使用onnx,首先我们就自己生成一个onnx文件,请大家准备一下以下需要的[python]环境

cpp 复制代码
python 版本>=3.8 我的机子比较老,只能装3.8
安装torch,可以使用命令行pip install torch
安装netron,可以使用命令行pip install netron
安装onnx,可以使用命令行pip install onnx

2、做好以上准备工作,我们就可以编写一个py文件,命名为create_onnx.py,内容如下:

python 复制代码
#======================================================================#

# 导入依赖库
import torch

#======================================================================#

# 打印pytorch基本信息
print("pytorch版本:",torch.__version__)
print("已安装pytorch版本是否支持英伟达显卡",torch.cuda.is_available())

# 自定义网络必须直接或间接继承自torch.nn.Module
class Net(torch.nn.Module):
    def __init__(self):
        super(self.__class__,self).__init__()
        self.linear=torch.nn.Linear(1,1)

    def forward(self,x):
        return self.linear(x)

#======================================================================#

# 训练自定义网络

# 实例化一个自定义网络对象,用于以下训练
net=Net()

# 选择平方差为标准损失函数
critision=torch.nn.MSELoss()
# 选择随机梯度下降的优化器,学习率设为0.01
optimizer=torch.optim.Adam(net.parameters(),lr=0.01)

# 训练的输入
x=torch.FloatTensor([[0],[1],[2],[3]])
# 训练的输出
y=torch.FloatTensor([[5],[7],[9],[11]])

# 训练3000轮
for epoch in range(1,3001):
    Y=net(x)
    loss=critision(Y,y)
    # 每训练100轮打印一次损失值以便于观察是否收敛
    if epoch%100==0:
        print(f"epoch:{epoch},loss:{loss.item()}")
    # 自动求导
    optimizer.zero_grad()
    # 反向传播
    loss.backward()
    # 更新参数
    optimizer.step()

#======================================================================#

# 保存模型为onnx格式,方便c#调用

# 输入参数格式为1行1列的数组
input_parameter=torch.randn(1,1)
# 导出onnx格式前务必先调用eval函数
net.eval()
with torch.no_grad():
    torch.onnx.export(net,# 自定义的网络对象
                      input_parameter, # 输入参数格式
                      "linear.onnx", # 导出onnx格式文件名称
                      opset_version=11, # 导出onnx指定算子版本
                      input_names=["input"], # 输入参数名称
                      output_names=["output"]) # 输出参数名称
#======================================================================#

命令行直接运行它,过一会它训练完毕,就会给我们生成onnx文件,名称为linear.onnx

3、编写另一个py文件,命名为watch_onnx.py,内容如下:

python 复制代码
import netron
netron.start("linear.onnx")

命令行直接运行它,过一会浏览器会直接显示出此onnx文件的推理图全过程参数

4、观察此onnx文件的输入输出,其输入为1x1的数组,输出也是1x1的数组。同时注意到它的意义,输入是[[x]],输出是[[y]],于是我们可以开始编写C#程序了。

正题[C#调用onnx]

1、新建一个DotNet控制台项目,千万别选成了DotNetFramework,命名为UseOnnx

2、NuGet中安装onnxruntime,由于只是简单入门介绍 ,这里我们选择cpu版本的onnx运行时安装即可,图中就是cpu的onnx运行时库

3、项目和依赖都准备好了,开始着手C#程序的编写,把Program.cs内容改为:

cs 复制代码
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using System;
using System.Collections.Generic;

namespace UseOnnx
{
    class Program
    {
        static void Main(string[] args)
        {
            //onnx文件路径,注意把onnx文件放到我们生成程序同级目录下
            string onnx_path = @"linear.onnx";
            //根据onnx文件路径实例化一个推理对象
            using InferenceSession session = new InferenceSession(onnx_path);

            //稠密张量,其维度与模型的输入参数格式一致,1x1==>>new int[]{1,1}
            DenseTensor<float> tensor = new DenseTensor<float>(new int[] { 1, 1 });

            //测试的输入为101
            float x = 101f;

            //把输入赋值到张量中
            tensor[0, 0] = x;

            //构建输入
            List<NamedOnnxValue> inputs = new List<NamedOnnxValue>()
            {
                //onnx推理图的输入名称为input,参数格式为1x1,因此这样构建输入
                NamedOnnxValue.CreateFromTensor("input",tensor)
            };

            //进行推理,得到结果
            using IDisposableReadOnlyCollection<DisposableNamedOnnxValue> outputs = session.Run(inputs);

            //输出是二维数组
            float[,] results = (float[,])outputs[0].Value;

            //输出只有一个,它就是onnx推理结果
            float y = results[0, 0];

            Console.WriteLine($"when x is {x} , onnx calculate y is {y:0.0}");
        }
    }
}

开始运行,如果没报错的话,应该可以看到近似结果

207.0

由于我的系统是win7,跑程序的时候报错没找到onnxruntime.dll,就算把这个动态链接库拷贝到同级目录下也报同样错误,所以没法最后一步截图演示了。希望win10、win11的小伙伴知悉。

相关推荐
深度学习lover38 分钟前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
△曉風殘月〆39 分钟前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
API快乐传递者2 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
逐·風3 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
阡之尘埃4 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控