CoreML输入数组归一化:sklearn转换报错及iOS使用疑问
解决Sklearn Normalizer转CoreML及iOS中使用CoreML原生Normalizer的问题
一、解决Sklearn转CoreML时的num_dimensions报错问题
你遇到的这个报错是因为Sklearn的Normalizer是无状态的(调用fit()不会改变任何参数),CoreML转换器没办法自动推断输入特征的维度,所以必须显式指定num_dimensions参数,同时还要搭配feature_names一起传递。
修改后的代码如下:
from sklearn.preprocessing import Normalizer import coremltools # 初始化Sklearn的Normalizer,可指定归一化类型,默认是l2 normalized = Normalizer(norm='l2') # 转换时显式指定特征名和维度 # num_dimensions=1表示输入是一维数组;如果是二维特征矩阵(样本x特征),就设为2 coreml_model = coremltools.converters.sklearn.convert( normalized, feature_names=["input_features"], num_dimensions=1 ) # 保存CoreML模型 coreml_model.save("SklearnNormalizer.mlmodel")
简单说明参数:
feature_names:给输入特征命名,方便iOS端调用时识别输入输出num_dimensions:根据实际输入数据维度设置,1对应一维数组,2对应二维特征矩阵
二、iOS中使用CoreML原生Normalizer处理浮点数组
如果不想转Sklearn模型,直接用CoreML原生的Normalizer,步骤分为创建CoreML模型和iOS端调用两部分:
1. 用coremltools构建原生Normalizer模型
先通过Python代码生成符合要求的CoreML模型:
import coremltools as ct # 配置Normalizer的归一化类型,可选L1/L2/MAX,对应Sklearn的norm参数 normalizer_spec = ct.proto.FeatureEngineering_pb2.Normalizer() normalizer_spec.norm_type = normalizer_spec.L2 normalizer_spec.input_dimension = 1 # 输入维度,1表示一维数组 # 构建模型基础配置 model_spec = ct.proto.Model_pb2.Model() model_spec.specificationVersion = ct.utils.SPECIFICATION_VERSION model_desc = model_spec.description # 添加输入特征:这里假设输入是10个元素的一维浮点数组 input_feat = model_desc.input.add() input_feat.name = "input_array" input_feat.type.multiArrayType.dataType = ct.proto.FeatureTypes_pb2.ArrayFeatureType.FLOAT32 input_feat.type.multiArrayType.shape.append(10) # 设置数组长度 # 添加输出特征 output_feat = model_desc.output.add() output_feat.name = "normalized_array" output_feat.type.multiArrayType.dataType = ct.proto.FeatureTypes_pb2.ArrayFeatureType.FLOAT32 output_feat.type.multiArrayType.shape.append(10) # 将Normalizer配置绑定到模型 model_spec.normalizer.CopyFrom(normalizer_spec) # 保存模型 ct.models.MLModel(model_spec).save("CoreMLNativeNormalizer.mlmodel")
2. iOS Swift代码中调用模型处理浮点数组
把生成的.mlmodel文件拖进Xcode项目,Xcode会自动生成对应的模型类(比如这里是CoreMLNativeNormalizer),然后用下面的代码处理浮点数组:
import CoreML func normalizeFloatArray(_ inputArray: [Double]) -> [Double]? { // 加载CoreML模型 guard let model = try? CoreMLNativeNormalizer(configuration: .init()) else { print("模型加载失败") return nil } // 验证输入数组长度是否和模型定义一致(这里是10) guard inputArray.count == 10 else { print("输入数组长度不匹配模型要求") return nil } // 将Swift数组转换成MLMultiArray(CoreML要求的输入格式) guard let inputMultiArray = try? MLMultiArray(shape: [10], dataType: .float32) else { print("无法创建MLMultiArray") return nil } // 赋值给MLMultiArray for (index, value) in inputArray.enumerated() { inputMultiArray[index] = NSNumber(value: value) } // 创建模型输入并执行预测 let modelInput = CoreMLNativeNormalizerInput(input_array: inputMultiArray) guard let modelOutput = try? model.prediction(input: modelInput) else { print("归一化处理失败") return nil } // 将输出的MLMultiArray转换成Swift数组 let normalizedArray = (0..<modelOutput.normalized_array.count).map { modelOutput.normalized_array[$0].doubleValue } return normalizedArray } // 调用示例 let rawArray = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0] if let result = normalizeFloatArray(rawArray) { print("归一化结果:\(result)") }
这段代码的核心是把Swift的浮点数组转换成CoreML支持的MLMultiArray类型,传入模型得到归一化结果后,再转换回Swift数组供后续使用。
内容的提问来源于stack exchange,提问作者Spring
相关产品推荐
相关产品推荐

