Bloodline's Blog Notes and thoughts from Bloodline

Core ML(一)——初体验

Comments

Core ML lets you integrate a broad variety of machine learning model types into your app. In addition to supporting extensive deep learning with over 30 layer types, it also supports standard models such as tree ensembles, SVMs, and generalized linear models. Because it’s built on top of low level technologies like Metal and Accelerate, Core ML seamlessly takes advantage of the CPU and GPU to provide maximum performance and efficiency. You can run machine learning models on the device so data doesn’t need to leave the device to be analyzed.

-Apple’s Machine Learning Overview

苹果在 WWDC 2017 上除了 ARKit 之外还推出了另外一个万众瞩目的框架——Core ML。通过这个框架我们可以轻易地为 App 添加机器学习(Machine Learning)的功能。轻易到什么程度?写一个图像识别的 App 来体验下吧。

在此之前我也没有深入过解过神经网络(Neural Network)以及机器学习(Machine Learning)的知识。模型也是从这里下载的。

我是谁?我在哪?什么是 Machine Learning?道理我都不懂,但是还是做了一个高大上的 Machine Learning App。

关于 Machine Learning

首先我们要简单了解下机器学习(Machine Learning)。机器学习常见定义:机器学习是一门人工智能的科学,该领域的主要研究对象是人工智能,特别是如何在经验学习中改善具体算法的性能。经验学习的过程就是“训练”,而经验学习的所获得的“知识”,可以称之为“模型”。训练和建立模型的方法和过程比较复杂,但目前我们的目标是先使用模型构建有意思的 App,而且,通过 Apple 的 Core ML,可以让构建过程更轻松。

App 功能概述

App 的名字为 Pixabay4ML,主要是使用 Core ML 框架,通过模型来识别从 pixabay 随机下载的一张图片的内容。运气好的话,说不定可以加载到一张美女的图片哦。

创建项目

创建过程没有什么特别的,主要用到的 pod 库为:

  pod 'Alamofire',    '4.6.0'  #用于网络请求
  pod 'Fuzi',         '2.0.1'  #用于解析 html
  pod 'Kingfisher',   '4.5.0'  #用于加载图片

UI 界面的搭建没什么难度,顺便熟悉下 Swift 语法。

整合 Core ML Data 模型

接下来需要集成 Core ML 模型到我们的项目中。这里我们使用 Apple 提供的 Inception v3 模型。下载完成后加到项目中,可以查看模型的基础信息。

01

可以看到 Model Evaluation Parametersinputsoutputs 的类型。输入为 299×299 的图像,输出为字典和字符串,描述最可能的分类和可能性。Model ClassInceptionv3 的类型。点击右边的小箭头,可查看模型的定义。

02

代码部分,引入 CoreML 框架:

import CoreML

然后,声明 Inceptionv3 类型的变量,并在 viewDidLoad 初始化。

model = Inceptionv3()

输入转换

通过 Kingfisher 下载的图片需要进行转换为可输入的图片,这部分主要是 CoreImage 框架的知识:

func predictImage(_ image:UIImage) {
    
    //将图像转成 299*299 的正方形
    UIGraphicsBeginImageContextWithOptions(CGSize(width: 299, height: 299), true, 2.0)
    image.draw(in: CGRect(x: 0, y: 0, width: 299, height: 299))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    
//        将 newImage 转成 CVPixelBuffer,CVPixelBuffer 是在主存储器中保存像素的图像缓冲区,由于CV开头,所以它是属于 CoreVideo 模块的。
    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
    var pixelBuffer : CVPixelBuffer?
    let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(newImage.size.width), Int(newImage.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
    guard (status == kCVReturnSuccess) else {
        return
    }
    
    CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
    let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!)

    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    let context = CGContext(data: pixelData, width: Int(newImage.size.width), height: Int(newImage.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) //3

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

    UIGraphicsPushContext(context!)
    newImage.draw(in: CGRect(x: 0, y: 0, width: newImage.size.width, height: newImage.size.height))
    UIGraphicsPopContext()
    CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
}

预测

Inceptionv3 模型的预测方法 func prediction(image: CVPixelBuffer) throws -> Inceptionv3Output 的参数为 CVPixelBuffer 类型(299 * 299),这也是为什么在上面要先进行类型转换。

使用 Core ML 进行预测很简单:

/// 预测图片
guard let prediction = try? model.prediction(image: pixelBuffer!) else {
    return
}

print(prediction.classLabel)

运行一下,便可以输出预测的类型啦。

完善 UI

接下来进行 UI 的完善。将预测的结果信息显示到视图中。

classLabel.isHidden = false
classLabel.text = "可能是:\(prediction.classLabel)"

probLabel.isHidden = false
probLabel.text = "可能性为:\(String(describing: prediction.classLabelProbs[prediction.classLabel]!.description))"

测试一下,有的图片预测的结果偏差比较大,这是模型的问题。我们可以针对性的更换模型,或者限定一下图片的类型(在请求 url 中添加 cat=animals 参数),来提高预测的准确性。

感觉只写了几句代码就已经把机器学习功能实现了呢。

参考:

Apple - Core ML

Introduction to Core ML: Building a Simple Image Recognition App

代码:

文章中的代码都可以从我的GitHub Pixabay4ML找到。