You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Core ML图像分类模型对不同图像输出相同预测结果排查

问题:Core ML猫狗图像分类模型预测结果始终固定

我正在探索Apple Core ML框架,用Create ML制作了一个猫狗图像分类模型,数据集用的是Kaggle的猫狗图像分类数据集。生成.mlmodel文件后,在iOS App里预测时,不管输入猫还是狗的图像,输出结果全一样:{"cats": 0.6281524444894766, "dogs": 0.3718475555105234}。我试过多种图像缩放、像素转换(pixelBuffer)的方法,换了测试集里不同的图像,结果还是没变。请问这是怎么回事?

App代码

override func viewDidLoad() {
    if let img = UIImage(named: "dog_29.jpg") {
        predictImage(image: img)
    } else {
        print("image  not captured")
    }
}

private func predictImage(image: UIImage) {
    let inputImageSize: CGFloat = 299.0
    let minLen = min(image.size.width, image.size.height)
    let resizedImage = image.resize(to: CGSize(width: inputImageSize * image.size.width / minLen, height: inputImageSize * image.size.height / minLen))

    guard let pixelBuffer = resizedImage.pixelBuffer() else {
        fatalError()
    }
    
    do {
        let config = MLModelConfiguration()
        let model = try CatsAndDogs(configuration:config)
        let result = try model.prediction(image: pixelBuffer)
        print(result.target)
        print(result.targetProbability)
        print(result)
    } catch {
        print("image classification error")
    }
}

图像缩放与像素转换代码

func resize(to newSize: CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(CGSize(width: newSize.width, height: newSize.height), true, 1.0)
    self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
    let resizedImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return resizedImage
}

func pixelBuffer() -> CVPixelBuffer? {
    let width = self.size.width
    let height = self.size.height
    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
                 kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
    var pixelBuffer: CVPixelBuffer?
    let status = CVPixelBufferCreate(kCFAllocatorDefault,
                                     Int(width),
                                     Int(height),
                                     kCVPixelFormatType_32ARGB,
                                     attrs,
                                     &pixelBuffer)

    guard let resultPixelBuffer = pixelBuffer, status == kCVReturnSuccess else {
        return nil
    }

    CVPixelBufferLockBaseAddress(resultPixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
    let pixelData = CVPixelBufferGetBaseAddress(resultPixelBuffer)

    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    guard let context = CGContext(data: pixelData,
                                  width: Int(width),
                                  height: Int(height),
                                  bitsPerComponent: 8,
                                  bytesPerRow: CVPixelBufferGetBytesPerRow(resultPixelBuffer),
                                  space: rgbColorSpace,
                                  bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) else {
        return nil
    }

    context.translateBy(x: 0, y: height)
    context.scaleBy(x: 1.0, y: -1.0)

    UIGraphicsPushContext(context)
    self.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
    UIGraphicsPopContext()
    CVPixelBufferUnlockBaseAddress(resultPixelBuffer, CVPixelBufferLockFlags(rawValue: 0))

    return resultPixelBuffer
}

可能的原因及解决方法

1. 模型训练环节存在问题

  • 检查数据集划分:确认训练集、验证集、测试集是否正确分离,标签是否对应正确。如果训练时猫的样本数量远多于狗,模型会倾向于输出“cats”类别,导致结果固定。
  • 查看Create ML训练报告:如果验证集准确率极低,说明模型根本没学会分类逻辑,只是在输出占比最高的类别。

2. 图像预处理与模型输入要求不匹配

这是最常见的问题,Core ML模型对输入的图像尺寸、像素格式、颜色空间、归一化规则要求严格,必须和训练时一致:

  • 输入尺寸不符:你当前只做了短边缩放,没有裁剪成模型要求的正方形(比如训练时设置的299×299)。非正方形输入会导致模型识别特征混乱。
    解决:缩放后裁剪中心区域的正方形,代码示例:
    // 缩放后裁剪中心正方形
    let cropRect = CGRect(x: (resizedImage.size.width - inputImageSize)/2,
                          y: (resizedImage.size.height - inputImageSize)/2,
                          width: inputImageSize,
                          height: inputImageSize)
    guard let croppedCGImage = resizedImage.cgImage?.cropping(to: cropRect) else { fatalError() }
    let finalImage = UIImage(cgImage: croppedCGImage)
    
  • 像素格式/颜色空间不匹配:你的pixelBuffer用了kCVPixelFormatType_32ARGB,但训练时Create ML默认的输入可能是RGB格式(无Alpha通道)。同时CGContext的bitmapInfo设置为noneSkipFirst,可能导致颜色通道顺序错乱。
    解决:右键.mlmodel文件→Show Quick Look→查看Input Description,确认模型要求的像素格式和颜色空间,调整pixelBuffer创建参数。比如换成kCVPixelFormatType_32RGB并对应修改bitmapInfo。
  • 缺失图像归一化:多数图像模型要求像素值归一化到特定范围(比如0-1或-1到1),Create ML训练时会自动处理,但App端需要手动实现。当前代码没有归一化步骤,输入像素值不在模型预期范围内。
    解决:在生成pixelBuffer后,对像素数据进行归一化处理,或者在绘制图像时调整颜色空间适配模型要求。

3. 模型初始化方式问题

你每次预测都重新初始化CatsAndDogs模型,虽然不会直接导致结果固定,但可能存在配置或缓存异常。建议将模型初始化移到viewDidLoad中,只初始化一次:

var model: CatsAndDogs?

override func viewDidLoad() {
    super.viewDidLoad()
    do {
        model = try CatsAndDogs(configuration: MLModelConfiguration())
    } catch {
        print("model init error")
    }
    // 加载图像并预测的代码
}

4. 测试图像加载验证

确认测试图像是否被正确加载:UIImage(named:)如果找不到图像,可能会复用之前的缓存(或返回nil)。可以在predictImage中打印图像的尺寸、哈希值,验证每次输入的是不同图像。


内容的提问来源于stack exchange,提问作者Gypsa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 17:35:56