在F#中运行ONNX模型遇类型错误,求正确类型定义方案
我尝试在.NET中运行用Python训练并转换为ONNX格式的Keras模型,使用ML.NET实现。该ONNX模型输入为两个float32张量:input_5(维度[unk_298,50])、input_6(维度[unk_297,50]),输出为float32张量out(维度[unk_299,1])。我参考微软官方文档将C#代码转换为F#代码,定义了OnnxInput和OnnxOutput类型,代码如下:
#r "nuget: Microsoft.ML" #r "nuget: Microsoft.ML.OnnxRuntime, 1.10.0" #r "nuget: Microsoft.ML.OnnxTransformer" open Microsoft.ML open Microsoft.ML.Data open Microsoft.ML.Transforms.Onnx open Microsoft.ML.OnnxRuntime.Tensors open System open System.IO [<CLIMutable>] type OnnxInput = { [<ColumnName("input_5");>] input1: DenseTensor<float32> [<ColumnName("input_6")>] input2: DenseTensor<float32> } [<CLIMutable>] type OnnxOutput = { [<ColumnName("out")>] output: DenseTensor<float32> } let onnxModelPath = @"" let mlContext = new MLContext() let createFloat32DenseTensor (data: float32 array) (dimensions: int array) = let memory = Memory<float32>(data) let tensor = new DenseTensor<float32>(memory, dimensions) tensor let data = Array.create 50 0f let dimensions = [| 1; 50 |] let init = createFloat32DenseTensor data dimensions let initialOnnxInput = { input1 = init input2 = init } let getPredictionPipeline (mlContext: MLContext) = let inputColumns = [|"input_5"; "input_6"|] let outputColumns = [|"out"|] let onnxPredictionPipeline = mlContext.Transforms.ApplyOnnxModel( outputColumnNames = outputColumns, inputColumnNames = inputColumns, modelFile = onnxModelPath ) let emptyDataView = mlContext.Data.LoadFromEnumerable<OnnxInput>([||]) onnxPredictionPipeline.Fit(emptyDataView) let onnxPredictionPipeline = getPredictionPipeline mlContext let onnxPredictionEngine = mlContext.Model.CreatePredictionEngine<OnnxInput, OnnxOutput>(onnxPredictionPipeline) let testinputName = createFloat32DenseTensor outputResult dimensions let testInput = { input1 = createFloat32DenseTensor outputResult dimensions input2 = createFloat32DenseTensor outputResult dimensions } let prediction = onnxPredictionEngine.Predict testInput
运行let onnxPredictionPipeline = getPredictionPipeline mlContext时,出现错误:
System.ArgumentOutOfRangeException: Could not determine an IDataView type and registered custom types for member input1@ (Parameter 'rawType')
请问如何创建正确的类型来运行该预训练ONNX模型?
ML.NET无法直接识别DenseTensor<float32>作为IDataView的兼容类型,需要改用ML.NET原生支持的向量/数组类型来定义输入输出,具体修改如下:
修改输入输出类型定义
将DenseTensor<float32>替换为float32[],并通过VectorType属性指定张量的维度,让ML.NET正确映射到ONNX模型的张量输入:[<CLIMutable>] type OnnxInput = { [<ColumnName("input_5"); VectorType(1, 50)>] input1: float32[] [<ColumnName("input_6"); VectorType(1, 50)>] input2: float32[] } [<CLIMutable>] type OnnxOutput = { [<ColumnName("out"); VectorType(1, 1)>] output: float32[] }注意:
VectorType的参数要和ONNX模型输入维度对应,这里用[1,50]匹配测试数据维度,实际使用时可根据模型动态维度调整。调整张量创建逻辑
无需再创建DenseTensor,直接使用float32数组作为输入数据:// 直接生成对应长度的数组,无需封装为DenseTensor let data = Array.create (1*50) 0f let initialOnnxInput = { input1 = data input2 = data } // 测试输入直接用数组 let testInput = { input1 = outputResult // 确保outputResult是长度为50的float32数组 input2 = outputResult }预测结果转换(可选)
如果需要将输出数组转为DenseTensor做后续处理,可在得到预测结果后手动转换:let prediction = onnxPredictionEngine.Predict testInput let outputTensor = DenseTensor<float32>(prediction.output, [|1;1|])
修改后重新运行代码,即可解决类型识别错误。
内容的提问来源于stack exchange,提问作者Canadian_Hombre

