You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建Xamarin.TensorFlow.Lite目标检测RunForMultipleInputsOutputs输出对象

问题现象

使用Xamarin.TensorFlow.Lite的Interpreter.RunForMultipleInputsOutputs()方法执行目标检测推理时,运行到该方法抛出未将对象引用设置到对象的实例空引用异常,无法确定正确的输出对象构造逻辑。
本次使用的目标检测模型从Azure Custom Vision导出,共包含3个输出张量,符合TensorFlow Lite官方目标检测输出规范(不含检测计数字段):

  • detected_boxes:检测到的边界框,每个边界框表示为[x1, y1, x2, y2],(x1, y1)、(x2, y2)分别为边界框两个对角点的坐标
  • detected_scores:每个检测框对应的置信度概率
  • detected_classes:每个检测框对应的类别索引
    目前公开可查的相关示例大多适配仅单输出的图像分类场景,参考TensorFlow官方Java API文档、GitHub同名issue中的示例代码编写的输出构造逻辑无法正常运行,报错代码如下:
int detectedBoxesOutputIndex = Interpreter.GetOutputIndex("detected_boxes"); // 0
int detectedClassesOutputIndex = Interpreter.GetOutputIndex("detected_classes"); // 1
int detectedScoresOutputIndex = Interpreter.GetOutputIndex("detected_scores"); // 2

int numDetections = Interpreter
    .GetOutputTensor(detectedClassesOutputIndex)
    .NumElements();

var outputDict = new Dictionary<Java.Lang.Integer, Java.Lang.Object>();

int batchSize = 1;
// new float [][][]
_OutputBoxes = CreateJaggedArray(batchSize, numDetections, 4);
_OutputClasses = CreateJaggedArray(batchSize, numDetections);
_OutputScores = CreateJaggedArray(batchSize, numDetections);

var mOutputBoxes = OutputBoxes;
var mOutputClasses = OutputClasses;
var mOutputScores = OutputScores;

Java.Lang.Object[] inputArray = { imageByteBuffer };

var outputMap = new Dictionary<Java.Lang.Integer, Java.Lang.Object>();
outputMap.Add(new Java.Lang.Integer(detectedBoxesOutputIndex), mOutputBoxes);
outputMap.Add(new Java.Lang.Integer(detectedClassesOutputIndex), mOutputClasses);
outputMap.Add(new Java.Lang.Integer(detectedScoresOutputIndex), mOutputScores);

// 运行到此处抛出空引用异常
Interpreter.RunForMultipleInputsOutputs(inputArray, outputMap);

已完成模型有效性、图像ByteBuffer预处理流程验证:调用单输出方法Interpreter.Run(img, output)时,可正常获取float[64][4]格式的detected_boxes张量输出,仅多输出调用失败。

故障原因

空引用异常来自两个Xamarin绑定Java库的典型适配问题:

  1. RunForMultipleInputsOutputs方法的第二个参数要求传入实现Java侧java.util.Map接口的对象,C#原生Dictionary<,>没有实现该Java接口,传入后Java层无法识别容器结构,直接读取到空值
  2. 代码中用CreateJaggedArray生成的C#交错数组是.NET特有类型,无法被Xamarin绑定层自动映射为Java原生的多维浮点数组,Java侧读取输出缓冲区时拿到无效引用
修复方案
  1. 替换输出容器:使用Java.Util.HashMap代替C#原生Dictionary作为输出存储结构
  2. 替换数组创建逻辑:通过Java反射API创建Java原生类型的多维数组,不要使用C#的交错数组或.NET原生多维数组
    修正后的可运行代码如下:
int detectedBoxesOutputIndex = Interpreter.GetOutputIndex("detected_boxes");
int detectedClassesOutputIndex = Interpreter.GetOutputIndex("detected_classes");
int detectedScoresOutputIndex = Interpreter.GetOutputIndex("detected_scores");

int numDetections = Interpreter
    .GetOutputTensor(detectedClassesOutputIndex)
    .NumElements();
int batchSize = 1;

// 创建Java原生多维数组,替代C#交错数组
var boxesArray = Java.Lang.Reflect.Array.NewInstance(
    Java.Lang.Class.FromType(typeof(float)),
    batchSize, numDetections, 4
);
var classesArray = Java.Lang.Reflect.Array.NewInstance(
    Java.Lang.Class.FromType(typeof(float)),
    batchSize, numDetections
);
var scoresArray = Java.Lang.Reflect.Array.NewInstance(
    Java.Lang.Class.FromType(typeof(float)),
    batchSize, numDetections
);

Java.Lang.Object[] inputArray = { imageByteBuffer };
// 使用Java HashMap替代C# Dictionary
var outputMap = new Java.Util.HashMap();
outputMap.Put(new Java.Lang.Integer(detectedBoxesOutputIndex), boxesArray);
outputMap.Put(new Java.Lang.Integer(detectedClassesOutputIndex), classesArray);
outputMap.Put(new Java.Lang.Integer(detectedScoresOutputIndex), scoresArray);

// 正常执行推理
Interpreter.RunForMultipleInputsOutputs(inputArray, outputMap);

// 推理完成后读取结果即可
_OutputBoxes = (float[][][]) boxesArray;
_OutputClasses = (float[][]) classesArray;
_OutputScores = (float[][]) scoresArray;

注意:如果模型的detected_classes输出是整数类型,需要将对应数组创建时的类型替换为typeof(int),读取时强转为int[][]即可。

内容的提问来源于stack exchange,提问作者TwoFingerRightClick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:51:22