WonderPlanet Tech Blog

アドバンストテクノロジー部やCTO室のメンバーを中心に最新の技術情報を発信しています。

Core MLを利用した機械学習とVisionでの画像認識

先日リリースされたiOS 11でCore MLとVisionフレームワークが新たに追加されました。
これはWWDC 2017で発表されたもので、Core MLはiOS上で機械学習の学習モデルを利用するための仕組みで、Visionは画像認識に関する機能を集めたフレームワークです。
これらの機能でどんなことが出来るのか紹介します。

Core MLでできること

学習モデルをiOS上で取り扱うための仕組みです。
学習モデルに何かしらの判断をさせたいデータを渡し、その結果を受け取るための橋渡しをしてくれます。
クラウドやサーバー上ではなく、iOS端末内で機械学習モデルを利用します。
あらかじめ用意した学習モデルを端末内で利用するもので、学習モデルの再学習をするものではありません。

学習モデルをiOSアプリで利用するには

coremltools」というPythonで動作するツールが用意されています。
Xcode上で学習モデルを利用するには「.mlmodel」という形式に変換する必要があり、coremltoolsでその変換を行います。

coremltoolsが対応している学習モデルの種類

Model Family Supported Packages
Neural NetworksKeras (1.2.2, 2.0.4+)
Caffe 1.0
Tree EnsemblesXGboost (0.6)
scikit-learn 0.18.1
Generalized Linear Modelsscikit-learn (0.18.1)
Support Vector MachineslibSVM (3.22)
scikit-learn (0.18.1)
Feature Engineeringscikit-learn (0.18.1)
Pipelinesscikit-learn (0.18.1)
coremltoolsの環境構築

大まかな手順は以下の通りです。

  1. virtualenvでPythonが動く環境用意する。
  2. pip install -U coremltoolsでツールをインストールする。
  3. coremltoolsを利用するために必要な下記のツールをpipでインストールする。
    ・numpy (1.12.1+)
    ・protobuf (3.1.0+)
    ・Keras (1.2.2+, 2.0.4+)
    ・Tensorflow (1.0.x, 1.1.x)
    ・Xgboost (0.6+)
    ・scikit-learn (0.15+)
    ・libSVM

詳細なインストール手順はcoremltoosのドキュメントを参照してください。

変換の例(.h5 → .mlmodel)

TensorFlowとKerasで作成した犬と猫の画像をどちらか判別する学習モデル「model.h5」をXcodeで扱える形式「convertedmodel.mlmodel」 に変換する例です。
以下の様なPythonコードをターミナルで実行します。
.mlmodelに変換されたファイルをXcodeのプロジェクト内に取り込むことができます。

from keras import backend as K
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Flatten, Convolution2D, MaxPooling2D
from keras.optimizers import Adadelta
import keras

import coremltools
path = 'model.h5'

# kerasで作成した学習モデルの変換をするメソッド。
# 入力を画像としています。入力した画像が”dog”と”cat”の2種類のラベルで分類されます。
coreml_model = coremltools.converters.keras.convert(
    path, 
    image_input_names='image', 
    is_bgr = True, 
    image_scale = 1.0, 
    predicted_feature_name = "label", 
    class_labels = ['dog', 'cat'])

# 変換後のファイルを出力する
coreml_model.save('convertedmodel.mlmodel')

coremltoolsのドキュメント
https://developer.apple.com/documentation/coreml/converting_trained_models_to_core_ml

Visionでできること

主に画像認識の機能を備えたフレームワークです。
機能としては、以下になります。

  • Face Detection and Recognition(顔の検出)
  • Machine Learning Image Analysis(機械学習での画像分析)
  • Barcode Detection(バーコード認識)
  • Image Alignment Analysis(画像の位置合わせ)
  • Text Detection(文字認識)
  • Horizon Detection(地平線認識)
  • Object Detection and Tracking(物体の移動トラッキング)

それぞれどういった事ができるのか、説明します。

Face Detection and Recognition(顔の検出)

カメラやイメージピッカーで選択した写真の中から人の顔を検出し位置・範囲を特定します。
ランドマーク(目、鼻、口)の位置の検出も可能です。 f:id:HidehikoKondo:20170928192044p:plain f:id:HidehikoKondo:20170928192100p:plain

Machine Learning Image Analysis(機械学習での画像分析)

別途作成したラベル付き画像を学習させたモデルに、画像を認識させ、モデルの学習内容に応じて分類します。
この記事の後半で実装例を紹介します。

Barcode Detection(バーコード認識)

QRコードなどバーコードの読み込みます。 AVFoundationフレームワークにバーコードを読み込む機能はありましたが、同時に複数のバーコードを認識できるなどの違いがあります。

Image Alignment Analysis(画像の位置合わせ)

アフィン変換、ホモグラフィック変換、画像レジストレーションなどの画像処理をしてくれるクラスです。
写真をつなぎ合わせてパノラマ写真の様な画像の作成などができます。
f:id:HidehikoKondo:20170928192340p:plain

Text Detection(文字認識)

画像内の文字を認識し、その位置と範囲の特定をします。
1文字毎と文節毎で位置と範囲の特定ができる。日本語でも認識することが可能です。
※認識した文字が「A」とか「あ」であるとか、OCRの様な機能ではありません。それを実現するには追加で実装が必要となります。 f:id:HidehikoKondo:20170928191958p:plain

Horizon Detection(地平線認識)

風景などの写真でどのくらい傾いているのかを取得できます。
取得した値を使うことで、傾いている写真を回転させて、地平線に対して水平になるように補正できます。 f:id:HidehikoKondo:20171002162340p:plain

Object Detection and Tracking(物体の移動トラッキング)

カメラで撮影している被写体の移動を検知し、位置をトラッキングします。 f:id:HidehikoKondo:20170928192401p:plain

Machine Learning Image Analysisの利用例

ここからは「Machine Learning Image Analysis」の実装例を説明します。
XcodeでVGG16学習モデルを取り込み、iOSアプリで写真に写っている物体が何であるかの認識をさせてみましょう。

動作環境
  • iOS11をインストールしたiOS端末
  • Xcode 9
  • Swift 4.0
  • VGG16学習モデル(.mlmodelに変換したもの)
学習モデルの入手

coremltoolsを使うことで、自分で作成した学習モデルを扱うこともできますが、
今回はお手軽にAppleが公開している.mlmodelに変換済みの学習モデルを用います。
下記のURLからVGG16の学習モデルをダウンロードしてください。
https://developer.apple.com/machine-learning/ f:id:HidehikoKondo:20170929125652p:plain

学習モデルの取り込み

ダウンロードした「VGG16.mlmodel」をXcodeにドラッグ&ドロップします。
Target Membershipのチェックボックスを忘れずにチェックしておきます。
Model Evaluation Parametersの欄を見ると、学習モデルの入力が画像で、出力は文字列でラベルが返ってくることがわかります。
f:id:HidehikoKondo:20170929142843p:plain

コード
import UIKit
import CoreML
import Vision
import ImageIO


class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    @IBOutlet weak var cameraView: UIImageView!
    @IBOutlet weak var resultLabel: UILabel!

    var inputImage: CIImage!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func imagePickerController(_ imagePicker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        self.resultLabel.text = "Analyzing Image…"
        if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
            self.cameraView.contentMode = .scaleAspectFit
            self.cameraView.image = pickedImage
        }
        imagePicker.dismiss(animated: true, completion: {
            guard let uiImage = info[UIImagePickerControllerOriginalImage] as? UIImage
                else { fatalError("no image from image picker") }
            guard let ciImage = CIImage(image: uiImage)
                else { fatalError("can't create CIImage from UIImage") }
            let orientation = CGImagePropertyOrientation(rawValue: UInt32(uiImage.imageOrientation.rawValue))
            self.inputImage = ciImage.oriented(forExifOrientation: Int32(orientation!.rawValue))

            //リクエストハンドラの作成。ここでカメラで撮影した画像を渡します。
            let handler = VNImageRequestHandler(ciImage: self.inputImage)
            do {
                try handler.perform([self.classificationRequest_vgg])
            } catch {
                print(error)
            }
        })
    }

    //VGG16学習モデルで画像を認識させるリクエストの作成
    lazy var classificationRequest_vgg: VNCoreMLRequest = {
        do {
            var model: VNCoreMLModel? = nil
            model = try! VNCoreMLModel(for: VGG16().model)
            return VNCoreMLRequest(model: model!, completionHandler: self.handleClassification)
        } catch {
            fatalError("can't load Vision ML model: \(error)")
        }
    }()

    //学習モデルが持っているラベルに応じて分類した結果の表示。分類結果の1個目(一番confidenceが高いもの)を表示します。
    //分類結果はVNClassificationObservation型のオブジェクトで返ってきます。
    func handleClassification(request: VNRequest, error: Error?) {
        guard let observations = request.results as? [VNClassificationObservation]
            else { fatalError("unexpected result type from VNCoreMLRequest") }
        guard let best = observations.first
            else { fatalError("can't get best result") }

        DispatchQueue.main.async {
            var classification: String = (best.identifier);
            self.resultLabel.text = "Classification: \"\(classification)\" Confidence: \(best.confidence)"
        }
    }

    @IBAction func openCamera(_ sender: Any) {
        let sourceType:UIImagePickerControllerSourceType = UIImagePickerControllerSourceType.camera
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
            let cameraPicker = UIImagePickerController()
            cameraPicker.sourceType = sourceType
            cameraPicker.delegate = self
            self.present(cameraPicker, animated: true, completion: nil)
        } else {
            print("error")
        }
    }

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
}

storyboardでは撮影した写真用のUIImageView・結果表示のラベル・カメラ希望のボタンを配置して、IBOutletとIBActionの接続をします。

f:id:HidehikoKondo:20170929150243p:plain

カメラでAppleのMagic Mouseを撮影してみました。
ちゃんとマウスとして認識されていますね。

f:id:HidehikoKondo:20170929150937p:plain

まとめ

このようにCore MLで学習モデルをiOSアプリで扱うことが出来るようになりました。
iOSアプリで学習モデルと扱うのにサーバーとの通信が必要なくなったことで、モバイル環境でも利用しやすくなります。
また、Visionフレームワークで今までは困難だった画像認識も手軽に行うことが出来るようになります。
iOSアプリで学習モデルが扱えることや、画像認識の機能を駆使することで、新たなアプリのアイデアやサービスが出てくるのではないでしょうか?
今後もモバイル向けに提供される新機能の動向を見ていかねばと思います。
次回以降の記事で顔認識などの機能の実装例も紹介できればと思っています。
お楽しみに。