使用多维数组作为 CoreML 模型输出

Working with a Multidimensional Array as a CoreML Model output

我已经使用 Microsoft 的 customvision.ai 服务训练了 对象检测 CoreML 模型。我将其导出以在我的应用程序中使用,以使用相机实时识别某些对象。然而,CoreML 模型输出一个 double 类型的 MultiArray。我不知道如何破译或使用这些数据,因为这是我第一次使用多维数组。我一直试图找出自定义视觉对象检测模型应该输出什么(例如 CGRect 或 UIImage),所以我知道我要将我的 MultiArray 转换成什么,但无法在 Microsoft 网站上的任何地方找到此信息。微软似乎有一个用于图像分类模型的演示应用程序,但没有用于对象检测模型的演示应用程序。

为了了解多维数组中可能包含的内容,我尝试将其打印出来并获得此结果...

Double 1 x 1 x 40 x 13 x 13 array

我也试过打印多维数组的 .strides 元素并得到这个...

[6760, 6760, 169, 13, 1]

我不知道这些信息是否真的有用,只是想向大家介绍我目前所做的一切。

所以,我的问题是这个 MultiArray 包含什么信息(它是类似于 UIImage 还是 CGRect?,还是不同的东西?)以及我如何将这个多维数组转换成一组有用的数据,我实际上可以使用?

我没有使用过 customvision.ai 服务,但我以前使用过对象检测模型。 13x13 阵列很可能是覆盖输入图像的网格。对于此数组中的每个单元格——通常对应于原始图像中的 32x32 像素块——有 40 个数字的预测。

这在一定程度上取决于哪种模型 customvision.ai 使用这 40 个数字的含义。但通常它们包含一个或多个边界框的坐标以及 class 概率。

如果模型是 YOLO(这似乎很可能,因为它也有一个 13x13 的输出网格),每个单元格有多个预测。每个预测有 4 个数字来描述边界框,1 个数字来描述此边界框包含对象的概率,以及 num_classes 个具有不同 classes 概率的数字。

因此每个网格单元格有 (5 + num_classes) x num_predictions 个数字。如果模型对每个网格单元进行 5 次预测,并且您已对 3 classes 进行训练,则每个网格单元会得到 (5 + 3)*5 = 40 个数字。

请注意,我在这里做了很多假设,因为我对您的模型类型以及您训练的对象有多少 class 一无所知。

这 40 个数字可能还没有 真实的 边界框坐标。您可能需要为 "decode" 这些数字编写额外的代码。同样,此逻辑取决于模型类型。

我假设 customvision.ai 有一些关于如何执行此操作的文档或示例代码。

您还可以在我的几篇博文中阅读更多关于此主题的信息:

9 个月后,我在尝试解决这个确切问题时偶然发现了您的问题。今天找到解决方案后,我想我会 post 解决它。

看看这个 github 示例。

https://github.com/Azure-Samples/cognitive-services-ios-customvision-sample/tree/master/CVS_ObjectDetectorSample_Swift

它使用名为 MicrosoftCustomVisionMobile 的 Cocoapod。

那个 cocoapod 包含 CVSInference 框架,它有一个 class,CVSObjectDetector,它将为您完成解析 3 维 MLMultiArray 输出的所有繁重工作。您需要做的就是为它提供用于检测的 UIImage 和 运行 推理。然后,您可以使用 CVSObjectDetector 的强类型属性读取检测到的标识符、它们的边界框和置信度。确保在绘制之前将坐标转换回视图 space!

如果你像我一样在 Xamarin 中工作,你可以使用 sharpie 为 pod 创建 C# 绑定,然后你就可以开始工作了。

这是一个迟到的答案,但我遇到了同样的问题,这就是我的解决方案。你应该得到类似的预测:

guard let modelOutput = try? model.prediction(input: modelInput) else {
    fatalError("Unexpected runtime error.")
}

然后,根据您在模型中定义的输出名称(此处名称为“Identity”):

您应该能够像这样访问多维数组中的数据:

for i in 0..<apoiOutput.Identity.count {
    print(modelOutput.Identity[i].floatValue)
}