golang实现Open Neural Network Exchange(ONNX)接口的插件库onnx-go的使用

Golang 实现 Open Neural Network Exchange (ONNX) 接口的插件库 onnx-go 的使用

ONNX Logo Go Logo

这是一个 Go 语言实现的 Open Neural Network Exchange (ONNX) 接口库。

使用前须知

该项目最初由 owulveryck 创建,并于 2024 年 5 月 31 日归档。Orama 决定重振该项目,并将投入大量努力使其再次闪耀。目前我们正在积极维护它,如果您发现任何问题,请耐心等待。

概述

onnx-go 包含将 ONNX 二进制模型解码为计算后端的基本功能,并可以像其他 Go 库一样在代码中使用。关于 ONNX 的更多信息,请访问 onnx.ai

ONNX 规范的实现部分支持导入,但不支持导出。

愿景声明

对于需要在其代码中添加机器学习功能的 Go 开发者来说,onnx-go 是一个便于使用神经网络模型(软件 2.0)的包。与任何其他计算库不同,这个包不需要数据科学方面的特殊技能。

警告 API 是实验性的,可能会发生变化。

免责声明

这是一个新版本的 API。Gorgonia 的调整版本已被移除,现在与 Gorgonia 的主分支兼容。不过,一些操作符尚不可用。

添加了一个实用程序来运行模型库中的模型。请查看 examples 子目录。

安装

通过 go get 安装:

go get github.com/owulveryck/onnx-go

onnx-go 兼容 Go 模块。

示例

这些示例假设您有一个预训练的 model.onnx 文件可用。您可以从 ONNX 模型库下载预训练模型。

非常简单的示例

这个示例只是将图解码到一个简单的后端中。然后您可以对生成的图执行任何操作。

// 创建一个后端接收器
backend := simple.NewSimpleGraph()
// 创建一个模型并设置执行后端
model := onnx.NewModel(backend)

// 读取 onnx 模型
b, _ := ioutil.ReadFile("model.onnx")
// 将其解码到模型中
err := model.UnmarshalBinary(b)

运行预训练模型的简单示例

这个示例使用 Gorgonia 作为后端。

import "github.com/owulveryck/onnx-go/backend/x/gorgonnx"

目前,Gorgonia 没有实现 ONNX 的所有操作符。因此,模型库中的大多数模型都无法工作。通过在后端添加更多操作符,情况会逐渐好转。

您可以在此处找到测试示例的列表和覆盖率。

func Example_gorgonia() {
	// 创建一个后端接收器
	backend := gorgonnx.NewGraph()
	// 创建一个模型并设置执行后端
	model := onnx.NewModel(backend)

	// 读取 onnx 模型
	b, _ := ioutil.ReadFile("model.onnx")
	// 将其解码到模型中
	err := model.UnmarshalBinary(b)
	if err != nil {
		log.Fatal(err)
	}
	// 设置第一个输入,数字取决于模型
	model.SetInput(0, input)
	err = backend.Run()
	if err != nil {
		log.Fatal(err)
	}
	// 检查错误
	output, _ := model.GetOutputTensors()
	// 将第一个输出写入 stdout
	fmt.Println(output[0])
}

模型库

examples 子目录中,您将找到一个实用程序来运行模型库中的模型,以及一个使用 Tiny YOLO v2 分析图片的示例实用程序。

内部

ONNX protobuf 定义

onnx 的 protobuf 定义使用经典的 protoc 工具编译成 Go。定义可以在 internal 目录中找到。定义没有暴露出来,以避免对此仓库的外部依赖。实际上,pb 代码可以更改为使用更高效的编译器,例如 gogo protobuf,并且此更改对包的用户应该是透明的。

执行后端

为了执行神经网络,您需要一个能够执行计算图的后端(有关计算图的更多信息,请阅读此博客文章)。

此图表示机制:

Schema

onnx-go 不提供任何可执行的后端,但作为参考,提供了一个构建信息图的简单后端作为示例(请参阅 simple 子包)。Gorgonia 是 ONNX-Go 的主要目标后端。

后端实现

后端基本上是一个可以对其节点应用操作的加权有向图。它应该满足以下接口:

type Backend interface {
	OperationCarrier
	graph.DirectedWeightedBuilder
}
type OperationCarrier interface {
	// 在图的节点上应用操作
	// graph.Node 是一个数组,因为它允许处理多个输出
	// 例如,一个分割操作返回 n 个节点...
	ApplyOperation(Operation, ...graph.Node) error
}

除了操作符,一个节点可以携带一个值。值被描述为 tensor.Tensor。为了携带数据,图的 Node 应该满足以下接口:

type DataCarrier interface {
	SetTensor(t tensor.Tensor) error
	GetTensor() tensor.Tensor
}

后端测试

onnx-go 提供了一些实用程序来测试后端。访问 testbackend 包以获取更多信息。

贡献

欢迎贡献。最终将编写贡献指南。同时,您可以提出问题或发送 PR。您也可以通过 Twitter 或 gophers’ slack 联系我(我在两者上都是 @owulveryck)。

该项目旨在成为一个安全、欢迎协作的空间,贡献者应遵守贡献者公约行为准则。

作者

Olivier Wulveryck

许可证

MIT。


更多关于golang实现Open Neural Network Exchange(ONNX)接口的插件库onnx-go的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Open Neural Network Exchange(ONNX)接口的插件库onnx-go的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用onnx-go实现ONNX接口的Golang插件库

ONNX (Open Neural Network Exchange) 是一种用于表示深度学习模型的开放格式,onnx-go是一个Golang实现的ONNX运行时库,允许在Go环境中加载和运行ONNX模型。

安装onnx-go

首先安装onnx-go库:

go get github.com/owulveryck/onnx-go

基本使用示例

1. 加载ONNX模型

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/owulveryck/onnx-go"
	"gorgonia.org/tensor"
)

func main() {
	// 1. 加载ONNX模型文件
	model := onnx.NewModel(onnx.NewGraph())
	
	file, err := os.Open("model.onnx")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	
	err = model.UnmarshalBinary(file)
	if err != nil {
		log.Fatal(err)
	}

	// 2. 准备输入数据
	inputT := tensor.New(
		tensor.WithShape(1, 3, 224, 224), // 示例输入形状
		tensor.WithBacking([]float32{...}), // 填入实际输入数据
	)

	// 3. 创建输入输出映射
	input := make(map[string]interface{})
	output := make(map[string]interface{})
	
	// 获取输入节点名称(通常需要查看模型文档)
	inputName := model.Graph().Input[0].Name
	input[inputName] = inputT
	
	// 4. 运行模型
	err = model.Run(input, output)
	if err != nil {
		log.Fatal(err)
	}

	// 5. 获取输出
	for name, value := range output {
		fmt.Printf("Output %v: %v\n", name, value)
	}
}

2. 使用后端加速

onnx-go支持不同的后端计算引擎,例如Gorgonia:

import (
	"github.com/owulveryck/onnx-go/backend/x/gorgonnx"
)

func main() {
	// 创建带有Gorgonia后端的模型
	backend := gorgonnx.NewGraph()
	model := onnx.NewModel(backend)
	
	// 其余代码与前面相同...
}

高级用法

1. 处理多输入输出

// 准备多个输入
input1 := tensor.New(tensor.WithShape(1, 3), tensor.WithBacking([]float32{1, 2, 3}))
input2 := tensor.New(tensor.WithShape(1, 2), tensor.WithBacking([]float32{4, 5}))

inputs := map[string]interface{}{
	"input1": input1,
	"input2": input2,
}

outputs := make(map[string]interface{})

err := model.Run(inputs, outputs)
if err != nil {
	log.Fatal(err)
}

for name, value := range outputs {
	fmt.Printf("%s: %v\n", name, value)
}

2. 获取模型元信息

// 获取模型输入输出信息
fmt.Println("Model inputs:")
for _, input := range model.Graph().Input {
	fmt.Printf("  Name: %v\n", input.Name)
	fmt.Printf("  Type: %v\n", input.Type)
}

fmt.Println("Model outputs:")
for _, output := range model.Graph().Output {
	fmt.Printf("  Name: %v\n", output.Name)
	fmt.Printf("  Type: %v\n", output.Type)
}

注意事项

  1. 性能考虑:Golang不是深度学习的主流语言,onnx-go的性能可能不如Python实现
  2. 操作符支持:不是所有ONNX操作符都被完全支持,使用前需检查兼容性
  3. 模型转换:确保模型已正确转换为ONNX格式
  4. 输入输出形状:需要与模型期望的形状完全匹配

完整示例:图像分类

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/owulveryck/onnx-go"
	"github.com/owulveryck/onnx-go/backend/x/gorgonnx"
	"gorgonia.org/tensor"
)

func main() {
	// 1. 初始化模型
	backend := gorgonnx.NewGraph()
	model := onnx.NewModel(backend)

	// 2. 加载ONNX模型
	file, err := os.Open("resnet18.onnx")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	
	err = model.UnmarshalBinary(file)
	if err != nil {
		log.Fatal(err)
	}

	// 3. 准备输入数据 (假设是1x3x224x224的图片)
	inputData := make([]float32, 1*3*224*224)
	// 这里应该填充实际的图像数据,通常需要预处理(归一化等)
	
	inputT := tensor.New(
		tensor.WithShape(1, 3, 224, 224),
		tensor.WithBacking(inputData),
	)

	// 4. 运行推理
	input := map[string]interface{}{"input.1": inputT}
	output := map[string]interface{}{}
	
	err = model.Run(input, output)
	if err != nil {
		log.Fatal(err)
	}

	// 5. 处理输出 (假设输出是1x1000的类别概率)
	outputTensor := output["output"].(*tensor.Dense)
	probabilities := outputTensor.Data().([]float32)
	
	// 找到最高概率的类别
	maxIndex, maxProb := 0, float32(0)
	for i, prob := range probabilities {
		if prob > maxProb {
			maxIndex, maxProb = i, prob
		}
	}
	
	fmt.Printf("Predicted class: %d with probability: %.2f%%\n", 
		maxIndex, maxProb*100)
}

onnx-go为Golang开发者提供了在Go生态中使用ONNX模型的途径,虽然功能可能不如Python生态完善,但对于需要集成深度学习模型到Go应用中的场景是一个有价值的工具。

回到顶部