如何为Vision框架CoreML创建MLFeatureProvider类适配MLMultiArray输入
报错核心原因
你当前调用的是MLModel的底层推理接口prediction(from:),这个接口要求入参必须是实现MLFeatureProvider协议的对象,不能直接传入MLMultiArray实例,所以才会触发类型不匹配的报错。
关于MLFeatureProvider的代码来源说明
- 如果将
.mlmodel文件拖入Xcode项目时,在文件检查器中开启了自动生成模型绑定类的选项,Xcode会自动生成对应模型的输入输出FeatureProvider实现,无需开发者手动编写 - 你当前的代码是通过
configureModel(url:)手动加载MLModel实例,没有使用Xcode自动生成的绑定类,因此需要自行实现极简的适配逻辑完成类型转换
具体实现步骤
1. 编写极简的输入适配器
创建一个遵循MLFeatureProvider协议的类,用来包装你的MLMultiArray输入,注意这里需要匹配你的CoreML模型定义中实际的输入特征名(可直接点击项目中的.mlmodel文件,在详情页的「Inputs」栏查看对应特征名称):
class MultiArrayInputProvider: MLFeatureProvider { private let inputArray: MLMultiArray private let featureName: String init(multiArray: MLMultiArray, featureName: String) { self.inputArray = multiArray self.featureName = featureName } func featureValue(for featureName: String) -> MLFeatureValue? { guard featureName == self.featureName else { return nil } return MLFeatureValue(multiArray: inputArray) } var featureNames: Set<String> { [featureName] } }
2. 替换原方法中的推理调用逻辑
将原来直接传入modelInput的部分,替换为适配器实例,同时修正原代码中吞掉错误的写法:
// Predictor类内部的推理方法 func makePrediction(){ let model: MLModel = configureModel(url: url) let poseMultiArrays = [MLMultiArray] = getPoseMultiArrays() let modelInput = MLMultiArray(concatenating: poseMultiArrays, axis: 0, dataType: .float) // 替换成你自己模型对应的输入特征名 let inputProvider = MultiArrayInputProvider( multiArray: modelInput, featureName: "你的模型输入特征名" ) do { // 传入适配后的provider实例完成推理 let prediction = try model.prediction(from: inputProvider) // 取输出结果时,同样根据模型定义的输出特征名取值即可 let outputResult = prediction.featureValue(for: "你的模型输出特征名")?.multiArrayValue } catch { print("推理执行异常: \(error)") } }
常见注意事项
- 不要使用
try?吞掉推理错误,这种写法会把维度不匹配、特征名不对应这类真实问题隐藏,排查问题时无法拿到具体报错信息 - 手写适配器的逻辑和Xcode自动生成的模型类内部实现完全一致,如果不需要手动加载自定义路径的模型,直接使用Xcode生成的模型绑定类,会自动完成
MLMultiArray到MLFeatureProvider的转换,省去手写适配类的步骤
内容的提问来源于stack exchange,提问作者The Swift Coder
相关产品推荐
相关产品推荐

