编辑:似乎这是 Coremltools 中的一个错误。见这里: https ://github.com/apple/coremltools/issues/691#event-3295066804
一句话总结:非最大抑制层输出四个值,但我只能使用这四个值中的两个作为后续层的输入。
我正在使用 Apple 的 Core ML Tools 包构建神经网络模型,并且添加了一个非最大抑制 (NMS) 层。根据文档,该层有四个输出:
- 输出1:box坐标,对应幸存的box。
- 输出2:box scores,对应于幸存的boxes。
- 输出 3:幸存框的索引。[这是我想在后续层中使用的输出]
- 输出4:NMS算法后选中的框数
我用一些简单的输入建立了一个测试模型,NMS 层正确地返回了上面列出的四个输出中的每一个的预期值。如果我随后在后续层中使用 output#1 或 output#2,那么我这样做没有问题。但是,如果我尝试在后续层中使用 output#3 或 output#4,我会收到一条错误消息,指出输入“在前面层的任何输出中都找不到”。
Jupyter 笔记本
复制此问题的最简单方法是下载并浏览此Jupyter Notebook。
或者,下面的示例代码也解决了我遇到的问题。
示例代码
我设置了一些示例输入数据,如下所示:
boxes = np.array(
[[[0.00842474, 0.83051298, 0.91371644, 0.55096077],
[0.34679857, 0.31710117, 0.62449838, 0.70386912],
[0.08059154, 0.74079195, 0.61650205, 0.28471152]]], np.float32)
scores = np.array(
[[[0.87390688],
[0.2797731 ],
[0.72611251]]], np.float32)
input_features = [('boxes', datatypes.Array(*boxes.shape)),
('scores', datatypes.Array(*scores.shape))]
output_features = [('output', None)]
data = {'boxes': boxes,
'scores': scores }
我已经建立了如下测试模型:
builder = neural_network.NeuralNetworkBuilder(input_features, output_features, disable_rank5_shape_mapping=True)
# delete the original output, which was just a placeholder while initializing the model
del builder.spec.description.output[0]
# add the NMS layer
builder.add_nms(
name="nms",
input_names=["boxes","scores"],
output_names=["nms_coords", "nms_scores", "surviving_indices", "box_count"],
iou_threshold=0.5,
score_threshold=0.5,
max_boxes=3,
per_class_suppression=False)
# make the model output all four of the NMS layer's outputs
for name in ["nms_coords", "nms_scores", "surviving_indices", "box_count"]:
builder.spec.description.output.add()
builder.spec.description.output[-1].name = name
builder.spec.description.output[-1].type.multiArrayType.dataType = ft.ArrayFeatureType.FLOAT32
# # add a linear activation layer (intentionally commented out)
# builder.add_activation(
# name="identity",
# non_linearity="LINEAR",
# input_name="surviving_indices",
# output_name="activation_output",
# params=[1.0,0.0])
# initialize the model
model = coremltools.models.MLModel(builder.spec)
此时,当我调用
output = model.predict(data, useCPUOnly=True)
print(output)
一切都按预期工作。
例如,如果我调用print(output['surviving_indices']
,结果是[[ 0. 2. -1.]]
(如预期的那样)。
但是,我无法使用surviving_indices
或box_count
输出作为后续层的输入。例如,如果我添加一个线性激活层(通过取消注释上面的块),我会得到以下错误:
Input 'surviving_indices' of layer 'identity' not found in any of the outputs of the preceding layers.
如果我使用box_count
输出(即通过input_name="box_count"
在add_activation
图层中设置),我也会遇到同样的问题。
我知道 NMS 层正确返回了名为surviving_indices
and的输出box_count
,因为当我调用时,print(builder.spec.neuralNetwork.layers[0])
我得到以下结果:
name: "nms"
input: "boxes"
input: "scores"
output: "nms_coords"
output: "nms_scores"
output: "surviving_indices"
output: "box_count"
NonMaximumSuppression {
iouThreshold: 0.5
scoreThreshold: 0.5
maxBoxes: 3
}
此外,如果我使用nms_coords
或nms_scores
输出作为线性激活层的输入,我没有任何问题。它将正确输出 NMS 层输出中未修改的nms_coords
或nms_scores
值。
我对为什么 NMS 层正确输出我想要的内容感到困惑,但是我无法在后续层中使用这些输出。