ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Paddle Inference Golang API:基于 cgo 与 C 预测库的 Go 语言推理实践指南

Paddle Inference Golang API:基于 cgo 与 C 预测库的 Go 语言推理实践指南 Paddle Inference Golang API基于 cgo 与 C 预测库的 Go 语言推理实践指南【免费下载链接】PaddlePArallel Distributed Deep LEarning: Machine Learning Framework from Industrial Practice 『飞桨』核心框架深度学习机器学习高性能单机、分布式训练和跨平台部署项目地址: https://gitcode.com/GitHub_Trending/pa/Paddle导读本文围绕 Paddle飞桨核心框架中 paddle/fluid/inference/goapi 目录下的 Go 语言推理 API 展开。该 API 以 C 预测库接口capi_exp 为底层、通过 cgo 桥接实现让 Go 服务能够直接加载 Paddle 训练产出的推理模型并完成预测。读完本文你将掌握从环境准备、C 预测库软链、到 Config/Predictor/Tensor 三大核心对象的使用全流程能够独立编写可运行、可部署的 Go 推理服务。一、架构定位Go API 如何与 Paddle 预测库交互从源码结构看Go API 是一个典型的「薄封装」层本身不含任何推理引擎逻辑全部预测能力来自 C 预测库。其调用链为Go 应用 → goapi (cgo 绑定) → capi_exp (C 接口) → Paddle Inference C 预测库具体证据体现在 lib.go 中通过#cgo指令声明了编译与链接依赖// #cgo CFLAGS: -I${SRCDIR}/paddle_inference_c/paddle/include // #cgo LDFLAGS: -L${SRCDIR}/paddle_inference_c/paddle/lib -lpaddle_inference_c import C这说明goapi 编译时要求在其源码目录下存在一个名为paddle_inference_c的软链接指向 C 预测库安装目录这是整个环境准备的核心前提。goapi 内部各文件分工清晰config.go封装PD_Config对应预测配置模型路径、GPU/XPU、TensorRT、OneDNN 等predictor.go封装PD_Predictor对应预测器tensor.go封装PD_Tensor对应输入/输出张量version.go提供Version()返回预测库版本utils.gocgo 与 Go 之间的 bool、字符串、数组类型转换辅助函数config_test.go配置对象的单元测试可作为 API 用法参考。模块名定义在 go.mod 中github.com/paddlepaddle/paddle/paddle/fluid/inference/goapiGo 版本要求go 1.15及以上。二、安装与环境准备1. 确认 Paddle 的 CommitIdGo 的模块版本依赖精确的提交号因此安装前先确认你所用 Paddle 版本的 CommitIdgit log -1记录输出中的完整提交号后续go get需要用到。2. 使用go get拉取 Go API 源码# 此处使用上一步记录的 CommitId假设为 0722297 COMMITID0722297 go get -d -v github.com/paddlepaddle/paddle/paddle/fluid/inference/goapi${COMMITID}-d表示仅下载而不安装-v输出详细日志。下载成功后源码会按 Go 模块缓存规则存放于 GOMODCACHE 目录。3. 下载或编译 C 预测库两种方式任选其一直接下载获取官方发布的paddle_inference_c预测库压缩包并解压源码编译编译 Paddle 时在 cmake 配置中打开-DON_INFERON即仅编译推理库编译完成后在构建目录下得到paddle_inference_c_install_dir安装目录。无论哪种方式最终都需要一个包含paddle/include头文件与paddle/lib动态库的 C 预测库目录这是 lib.go 中#cgo指令引用的目标。4. 软链将 C 预测库挂到 Go API 源码目录Go 1.15 起引入了GOMODCACHE环境变量go get默认将代码下载到该目录。先查看路径go env | grep GOMODCACHE在官网发布的 docker 镜像中该路径通常默认为/root/gopath/pkg/mod。随后进入 Go API 代码目录建立软链接将 C 预测库命名为paddle_inference_ceval $(go env | grep GOMODCACHE) # 按需修改最后的 goapi 版本号 cd ${GOMODCACHE}/github.com/paddlepaddle/paddle/paddle/fluid/inference/goapi\v0.0.0-20210623023452-0722297d9b8c/ ln -s ${PADDLE_C_DOWNLOAD_DIR}/paddle_inference_c_install_dir paddle_inference_c注意${PADDLE_C_DOWNLOAD_DIR}需要替换为你实际的 C 预测库所在路径。软链名称paddle_inference_c必须与#cgo指令中-I/-L引用的目录名完全一致。5. 运行单测验证环境bash test.shtest.sh 做了三件事下载测试模型若当前目录不存在mobilenetv1则下载 mobilenetv1 推理模型并解压用于真实预测验证设置LD_LIBRARY_PATH依次将 mklml、mkldnnOneDNN、paddle 主库、onnxruntime、paddle2onnx、phi、onednn 等动态库目录加入链接路径保证运行时能加载全部依赖export LD_LIBRARY_PATH$LD_LIBRARY_PATH:$PWD/paddle_inference_c/third_party/install/mklml/lib/:$PWD/paddle_inference_c/third_party/install/mkldnn/lib/:$PWD/paddle_inference_c/paddle/lib/ export LD_LIBRARY_PATH$LD_LIBRARY_PATH:$PWD/paddle_inference_c/third_party/install/onnxruntime/lib/:$PWD/paddle_inference_c/third_party/install/paddle2onnx/lib/ export LD_LIBRARY_PATH$LD_LIBRARY_PATH:${PADDLE_ROOT}/build/paddle/phi/ export LD_LIBRARY_PATH$LD_LIBRARY_PATH:$PWD/paddle_inference_c/third_party/install/onednn/lib/:${PADDLE_ROOT}/build/paddle_inference_install_dir/paddle/lib/执行测试go clean -testcache清空测试缓存后go test -v ./...运行全部单测。config_test.go中的TestNewConfig、TestOnednn、TestONNXRuntime会逐一验证配置对象的各开关方法运行通过即代表 cgo 编译链接与底层 C 库均工作正常。三、在 Go 中使用 Paddle 预测核心流程完整预测流程遵循「创建配置 → 创建预测器 → 取输入输出句柄 → 灌入数据 → 运行 → 取回结果」的标准步骤与 C/Python 推理接口保持一致。1. 创建预测配置config : paddle.NewConfig() config.SetModel(model_file, params_file)NewConfig()在 config.go 中对应PD_ConfigCreate()创建一个空的PD_Config对象。SetModel(model, params)用于组合模型program 与 params 分离为两个文件场景分别指定模型文件与参数文件路径与之对应还有SetModelDir(modelDir)设置非组合模型目录目录内包含__model__与参数文件SetProgFile(model)/SetParamsFile(params)单独设置组合模型的两个文件config_test.go中的TestNewConfig即用这种方式构造配置。2. 创建 Predictorpredictor : paddle.NewPredictor(config)predictor.go 中NewPredictor调用PD_PredictorCreate(config.c)创建预测器并通过runtime.SetFinalizer注册析构回调PD_PredictorDestroy由 Go GC 负责释放底层 C 资源避免手动管理内存。此外还提供Clone()方法克隆出独立预测器可用于多线程场景下复用已构建的推理引擎。3. 获取输入与输出 TensorinNames : predictor.GetInputNames() inHandle : predictor.GetInputHandle(inNames[0]) outNames : predictor.GetOutputNames() outHandle : predictor.GetOutputHandle(outNames[0])GetInputNames()/GetOutputNames()返回字符串切片内部通过 utils.go 的cvtToGoSliceString将 C 字符串数组转为 Go sliceGetInputHandle/GetOutputHandle按名称拿到张量句柄同样注册了 Finalizer 自动释放。若模型只有一个输入/输出直接取names[0]即可。4. 设置输入数据data : make([]float32, 1*3*224*224) for i : 0; i len(data); i { data[i] float32(i%255) * 0.1 } inHandle.Reshape([]int32{1, 3, 224, 224}) inHandle.CopyFromCpu(data)Reshape(shape []int32)重置张量形状通常仅用于输入张量内部调用PD_TensorReshapeCopyFromCpu(value interface{})利用反射reflect.ValueOf推断 Go slice 元素类型再分发到对应的 C 拷贝函数。源码 tensor.go 支持的数据类型与DataType常量一一对应Go 类型DataType 常量底层 C 调用[]float32Float32PD_TensorCopyFromCpuFloat[]int32Int32PD_TensorCopyFromCpuInt32[]int64Int64PD_TensorCopyFromCpuInt64[]uint8Uint8PD_TensorCopyFromCpuUint8[]int8Int8PD_TensorCopyFromCpuInt8传入不支持的 slice 类型时dataTypeOf会返回unsupported type错误。5. 设置 Lod变长序列场景对于 NLP 等变长输入需要为输入张量设置 LodLevel of Detail信息lod : make([][]uint, 2) for i : 0; i len(lod); i { lod[i] make([]uint, 2) // 设置输入... lod[i][0] 0 lod[i][1] 10 } inHandle.SetLod(lod)SetLod(lod [][]uint)在源码中通过C.malloc构造PD_TwoDimArraySize结构即std::vectorstd::vectorsize_t再调用PD_TensorSetLod下发读取时Lod()反向转换为 Go 的[][]uint。注意原文档示例中第二行lod[i][0] 10实为笔误正确写法是lod[i][1] 10本文已修正。6. 运行预测predictor.Run()对应PD_PredictorRun同步执行推理。7. 获取输出结果func numElements(shape []int32) int32 { n : int32(1) for _, v : range shape { n * v } return n } outData : make([]float32, numElements(outHandle.Shape())) outHandle.CopyToCpu(outData) fmt.Println(outHandle.Lod())outHandle.Shape()获取输出形状返回[]int32据此计算元素个数并预分配输出切片CopyToCpu将输出数据拷贝回 Go 内存支持的 Go 类型与CopyFromCpu完全对称outHandle.Lod()取回输出张量的 Lod 信息供需要按序列解析结果的场景使用。四、进阶配置硬件加速与推理调优Config对象是全部调优入口。除了基础的模型路径设置config.go 完整封装了 Paddle Inference 的各类加速能力可按需组合CPU 与通用优化SetCpuMathLibraryNumThreads(n)/CpuMathLibraryNumThreads()设置/查询 CPU 数学库线程数EnableONEDNN()开启 OneDNNMKL-DNN加速OnednnEnabled()查询状态SetONEDNNOp(opList)指定启用 OneDNN 的算子类型列表如[fc, conv]见TestOnednnSetOnednnCacheCapacity(capacity)设置 OneDNN 对不同输入形状的缓存容量默认 0 表示不缓存EnableOnednnBfloat16()/SetBfloat16Op(opList)开启 bfloat16 低精度推理并指定参与算子SwitchIrOptim(x)控制是否进行 IR 图优化关闭后行为等同 NativeConfigIrOptim()查询SwitchIrDebug(x)开启 IR 分析阶段调试会为每个 pass 生成 DOT 图EnableMemoryOptim(x)开启内存优化源码注释标注仍在开发中EnableProfile()开启 profiling 报告DisableGlogInfo()静默推理日志。GPU 与 TensorRTEnableUseGpu(memorySize uint64, deviceId int32)开启 GPU参数为 GPU 显存池初始大小MB与卡号UseGpu()、GpuDeviceId()、MemoryPoolInitSizeMb()、FractionOfGpuMemoryForPool()提供查询EnableGpuMultiStream()开启 GPU 多计算流当前实现为将计算流绑定到线程EnableTensorRtEngine(workspaceSize, maxBatchSize, minSubgraphSize, precision, useStatic, useCalibMode)开启 TensorRT 引擎precision取PrecisionFloat32/PrecisionInt8/PrecisionHalf三种精度常量SetTRTDynamicShapeInfo(minInputShape, maxInputShape, optimInputShape map[string][]int32, disableTrtPluginFp16)为 TensorRT 动态 shape 设置 min/max/opt 三档形状map的 key 为输入名EnableTunedTensorRtDynamicShape(shapeRangeInfoPath, allowBuildAtRuntime)结合CollectShapeRangeInfo(path)收集到的 shape 范围信息做动态 shape 调优EnableTensorRtDLA(dlaCore)、EnableVarseqlen()、DisableTensorRtOPs(ops)分别开启 DLA 加速、变长序列支持、禁用部分算子进入 TRT。XPUEnableXpu(l3Size, l3Locked, convAutotune, convAutotuneFile, transformerEencoderPrecision, transformerEncoderAdaptiveSeqlen, enableMultiStream)开启百度昆仑 XPU 支持参数依次为 L3 缓存大小最大 16M、L3 是否锁定、conv 算子自动调优开关及调优文件、multi_encoder 计算精度与变长输入开关、多流开关。模型与运行时管理SetModelBuffer(prog, params)直接从内存加载模型与参数ModelFromMemory()查询适合将模型打包进二进制或加密存储的场景SetOptimCacheDir(cacheDir)设置优化缓存目录EnableONNXRuntime()/EnableORTOptimization()开启 ONNX Runtime 后端及其优化DeletePass(pass)/AppendPass(pass)/InsertPass(idx, pass)/AllPasses()增删查 IR passTestNewConfig中演示了AppendPass(test_pass)后AllPasses()能查到、DeletePass后消失的行为Summary()返回配置信息的汇总字符串便于日志输出IsValid()校验当前配置是否合法。Predictor 生命周期管理predictor.go 除Run()外还提供ClearIntermediateTensor()清理预测器的中间张量TryShrinkMemory()释放临时张量以压缩显存/内存池返回实际释放字节数可能小于真实释放量因为部分内存不受 MemoryPool 管理。五、版本与类型速查paddle.Version()version.go返回底层 C 预测库版本字符串可用于运行时校验库与 API 的匹配关系PlaceType常量CpuPlace/GpuPlace/XpuPlace与DataType常量Float32/Int32/Int64/Uint8/Int8定义于 tensor.go对应 C 层 pd_types.h 中的类型枚举C 层数组结构PD_OneDimArrayInt32、PD_TwoDimArraySize、PD_OneDimArrayCstr等见 pd_types.h负责 Go slice 与 C 数组间的桥接Go 侧在使用后通过对应的PD_*Destroy函数释放。六、总结与建议Paddle Inference 的 Go API 通过「cgo C 预测库」的薄封装设计把完整的高性能推理能力以 Go 惯用的对象模型暴露出来Config管配置、Predictor管执行、Tensor管数据。实践中有几点值得注意软链是关键一步paddle_inference_c软链必须与 lib.go 中#cgo的-I/-L路径一致否则编译即失败运行时依赖库繁多务必参照 test.sh 完整设置LD_LIBRARY_PATHmklml、onednn、onnxruntime、phi 等否则运行时报找不到动态库内存由 Go 托管Predictor 与 Tensor 均通过runtime.SetFinalizer自动释放 C 资源无需手动 free但应避免持有大量未 GC 的句柄先用单测验证bash test.sh会下载 mobilenetv1 模型做真实推理验证是排查 cgo/链接问题的第一手段。掌握以上流程后你即可将 Paddle 训练好的模型无缝接入 Go 微服务、推荐系统或边缘推理程序复用 CPU 多线程、GPU、TensorRT、XPU 等全部底层加速能力。【免费下载链接】PaddlePArallel Distributed Deep LEarning: Machine Learning Framework from Industrial Practice 『飞桨』核心框架深度学习机器学习高性能单机、分布式训练和跨平台部署项目地址: https://gitcode.com/GitHub_Trending/pa/Paddle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表