CoreML模型规范-将输出类型更改为字典

问题描述

在过去一周中,我一直在努力对使用Google的AutoML Vision工具构建的分类器进行推断。

起初,我认为一切都会顺利进行,因为Google允许导出最终模型的CoreML版本。我以为只需要使用Apple的CoreML库即可使其工作。当我导出模型时,Google提供了带有分类标签的.mlmodel文件和dict.txt文件。对于当前模型,我有100个标签

这是我的Swift代码,可以在模型上进行推断。

private lazy var classificationRequest: VNCoreMLRequest = {
        do {

            let classificationModel = try VNCoreMLModel(for: NewGenusModel().model)

            let request = VNCoreMLRequest(model: classificationModel,completionHandler: { [weak self] request,error in
                self?.processClassifications(for: request,error: error)
            })

            request.imageCropAndScaleOption = .scaleFit
            return request
        }
        catch {
            fatalError("Error! Can't use Model.")
        }
    }()

    func classifyImage(receivedImage: UIImage) {

        let orientation = CGImagePropertyOrientation(rawValue: UInt32(receivedImage.imageOrientation.rawValue))

        if let image = CIImage(image: receivedImage) {
            dispatchQueue.global(qos: .userInitiated).async {

                let handler = VNImageRequestHandler(ciImage: image,orientation: orientation!)
                do {
                    try handler.perform([self.classificationRequest])
                }
                catch {
                    fatalError("Error classifying image!")
                }
            }
        }
    }

当我尝试传递UIImage在模型上运行推理时,问题开始了。原始模型的输入类型为MultiArray(Float32 1 x 224 x 224 x 3)。使用Coremltools库,我能够使用Python将输入类型转换为图像(颜色224 x 224)。

这有效,这是我的代码

import coremltools
import coremltools.proto.FeatureTypes_pb2 as ft

spec = coremltools.utils.load_spec("model.mlmodel")

input = spec.description.input[0]
input.type.imageType.colorSpace = ft.ImageFeatureType.RGB
input.type.imageType.height = 224
input.type.imageType.width = 224

coremltools.utils.save_spec(spec,"newModel.mlmodel")

我现在的问题是输出类型。我希望能够访问分类的置信度以及分类的结果标签。再次使用coremltools,我能够访问输出描述,我明白了。

name: "scores"
type {
  multiArrayType {
    dataType: FLOAT32
  }
}

我正在尝试通过以下方式进行更改:

f = open("dict.txt","r")
labels = f.read()

class_labels = labels.splitlines()
print(class_labels)
class_labels = class_labels[1:] # remove the first class which is background
assert len(class_labels) == 57

# make sure entries of class_labels are strings
for i,label in enumerate(class_labels):
  if isinstance(label,bytes):
    class_labels[i] = label.decode("utf8")

#classifier_config = ct.ClassifierConfig(class_labels)

output = spec.description.output[0]
output.type = ft.DictionaryFeatureType

不幸的是,这无法正常工作,我找不到任何可以帮助我的信息。

解决方法

ct.ClassifierConfig仅在转换模型时即调用ct.convert(...)时有用。

如果您已经具有mlmodel,则不能以这种方式更改类标签。您必须使用spec在mlmodel对象中更改它们。

鉴于该规格,您可以执行以下操作:

labels = spec.neuralNetworkClassifier.stringClassLabels 
del labels.vector[:]
new_labels = [ ... ] 
labels.vector.extend(new_labels)

coremltools.utils.save_spec(spec,"YourNewModel.mlmodel")

new_labels是标签列表。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...