我有一个PyTorch网络,我想将它部署到iOS设备上。简而言之,我不能在CoreML中为输入张量形状增加灵活性。
网络是一个convnet,它以RGB映像(存储为张量)作为输入,并返回相同大小的RGB映像。使用PyTorch,我可以输入任意大小的图像,例如,300x300图像的大小张量(1,3,300,300)。
为了将PyTorch模型转换为CoreML模型,我首先使用torch.onnx.export将其转换为ONNX模型。这个函数需要传递一个虚拟输入,这样它才能执行图形。所以我用了:
input = torch.rand(1, 3, 300, 300)我猜ONNX模型只接受大小(1,3,300,300)的图像/张量。现在,我可以使用onnx_coreml.convert函数将ONNX模型转换为CoreML模型。通过使用CoreML打印模型的规范描述,我得到如下内容:
input {
name: "my_image"
type {
multiArrayType {
shape: 1
shape: 3
shape: 300
shape: 300
dataType: FLOAT32
}
}
}
output {
name: "my_output"
type {
multiArrayType {
shape: 1
shape: 3
shape: 300
shape: 300
dataType: FLOAT32
}
}
}
metadata {
userDefined {
key: "coremltoolsVersion"
value: "3.1"
}
}模型的输入必须是大小的multiArrayType (1,3,300,300)。通过将该模型复制到XCode中,我可以在检查模型时看到,my_name列在“Input”部分下,并且预期它将是一个MultiArray (Float32 1 x 3 x 300 x 300)。到目前为止,一切都是连贯的。
我的问题是给输入形状增加灵活性。我试着在没有运气的情况下使用共同记忆工具。这是我的问题。这是我的代码:
import coremltools
from coremltools.models.neural_network import flexible_shape_utils
spec = coremltools.utils.load_spec('my_model.mlmodel')
shape_range = flexible_shape_utils.NeuralNetworkMultiArrayShapeRange()
shape_range.add_channel_range((3,3))
shape_range.add_height_range((64, 5000))
shape_range.add_width_range((64, 5000))
flexible_shape_utils.update_multiarray_shape_range(spec, feature_name='my_image', shape_range=shape_range)
coremltools.models.utils.save_spec(spec, 'my_flexible_model.mlmodel')我使用Python获得了以下规范描述:
input {
name: "my_image"
type {
multiArrayType {
shape: 1
shape: 3
shape: 300
shape: 300
dataType: FLOAT32
shapeRange {
sizeRanges {
lowerBound: 3
upperBound: 3
}
sizeRanges {
lowerBound: 64
upperBound: 5000
}
sizeRanges {
lowerBound: 64
upperBound: 5000
}
}
}
}
}只有3个指定的范围,这是有意义的,因为我只为通道、高度和宽度定义了一个范围,但没有为批处理大小定义范围。在XCode中,检查灵活的CoreML模型时会出现以下错误:
There was a problem decoding this CoreML document
validator error: Description of multiarray feature 'my_image' has a default 4-d shape but a 3-d shape range我很确定,当我在macOS project上的时候,它正在做另一个项目,但在这一点上,我什么也不确定。
我在用:
Catalina
谢谢你的帮助
发布于 2020-01-09 16:55:08
最简单的方法就是删除那个shape:1。就像这样:
del spec.description.input[0].shape[0]现在默认的形状也应该是三维的。
但是,我建议将输入的类型从多个数组更改为一个实际的图像。因为不管怎么说,你都要把它和图像一起使用。这将允许您将图像作为CVPixelBuffer或CGImage对象而不是MLMultiArray传递。
https://stackoverflow.com/questions/59662399
复制相似问题