CreateML 结果在应用程序中很糟糕,而在操场上却很完美

Posted

技术标签:

【中文标题】CreateML 结果在应用程序中很糟糕,而在操场上却很完美【英文标题】:CreateML results are awful at app while it's perfect in playground 【发布时间】:2019-07-17 10:22:24 【问题描述】:

我正在尝试用图像分类训练 MLModel。我创建了一个应用程序来创建图像以用作训练数据(最后将使用相同的过程来获得预测)。 我从 AvCaptureSession 获得 CVPixelBuffer,将其转换为 UIImage 并将其以 JPEG 格式保存到文档目录中。后来我给它们贴上标签,并在操场上用 CreateML 训练 MLModel。因为我收集了数千张图片,所以在操场上的结果是 %100。

但是当我将此模型集成到我的应用程序中并以相同的方式提供它时,结果很糟糕。我得到 CVPixelBuffer,将其转换为 UIImage(裁剪)并将裁剪后的图像转换为 CVPixelBuffer 并将其提供给模型。我必须将 UIImage 转换为 CVPixelBuffer,因为 CoreML 模型只有 CVPixelBuffer 除外。我使用这种方法将 UIImage 转换为 CVPixelBuffer:

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

    guard status == kCVReturnSuccess, let pixelBuffer = maybePixelBuffer else 
        return nil
    

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

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

    UIGraphicsPushContext(context)
    context.translateBy(x: 0, y: CGFloat(height))
    context.scaleBy(x: 1, y: -1)
    self.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
    UIGraphicsPopContext()

    CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
    return pixelBuffer

我认为我的结果很差,因为 CoreML 模型不喜欢转换后的 CVPixelBuffer。

有人有什么建议吗?

【问题讨论】:

【参考方案1】:

你不需要这些东西。让我们看一下文档:

class VNCoreMLRequest : VNImageBasedRequest

首先,VNImageBasedRequest 包含字段regionOfInterest: CGRect get set ,其中矩形是标准化的并且是左下角相对。 所以你不需要裁剪!只需指定 ROI。

其次,VNCoreMLRequest 本身有 var imageCropAndScaleOption: VNImageCropAndScaleOption get set 字段,您可以在其中指定当高/宽比与预期不匹配时如何操作(中心裁剪、缩放以适应/填充)。

【讨论】:

感谢您回答 Maxim,我正在裁剪图像,因为我没有只有一个感兴趣的区域。它可以增加到 50。因此,我将图像裁剪为(最多)50 块并将其提供给 ML 模型,模型会在合理的时间内返回结果。但就像我提到的,结果非常不准确。 所以?您可以向它提供 50 个具有不同 ROI 的图像请求。虽然我不明白你的用例。如果您需要多个对象,则需要一个对象检测器模型(即不是图像分类器)。 好吧,我用 Vision 检测对象,然后将它们从主图像中裁剪出来。然后将它们提供给 MLModel。检测对象不是问题,问题是 MLModel 的行为与游乐场不同。我用相同的数据喂它,唯一的区别是;我将它们转换为 UIImage,然后再次转换为 CVPixelBuffer。 也许颜色已经关闭?相机通常提供 BGRA(也不是 RGBA)。但是话又说回来,可以在 CVPixelBuffer 上进行裁剪而无需转换 - github.com/hollance/CoreMLHelpers/blob/master/CoreMLHelpers/… 我已经尝试了所有的RGBA/BGRA选项,结果都是一样的。但正如你所说,我会尝试裁剪像素缓冲区,并将其提供给 MLModel。我会让你知道结果。

以上是关于CreateML 结果在应用程序中很糟糕,而在操场上却很完美的主要内容,如果未能解决你的问题,请参考以下文章

React 本机选择器在 android 中看起来不错,但在 ios 中很糟糕

Swift 操场结果错误的位置

json appstore中的createml应用程序

CreateML App - 导出经过训练的 mlmodel 以在应用程序开发中使用

CreateML:“无法保存文档。”

反向传播神经网络