n番煎じではありますが,機械学習フレームワーク TensorFlow と Keras で学習したモデルを,iOS11 からの Core ML に与えて,簡単な顔識別のアプリを試作して見ました.試作ということで,データ収集など一部で手を抜いてます.ご了承ください.
ただいま絶賛放送中のNEW GAME!!の9人の主要キャラを対象した識別アプリです.UI等は,先行実装された記事を参考しました.ありがとうございます.
1. TensorFlow (Keras)
画像データはGoogle画像検索およびTumblrタグ検索のスクリプトを書いて集めました.APIの使用制限上,各キャラごとに多くの画像は集められなかったのですが,比較的キャラの描き分けがされている,作画が安定しているからたぶん大丈夫だろうと思います.
使用したCNN(畳み込みニューラルネットワーク)は以下のような簡単なものを設定しました.
model = Sequential()
model.add(Conv2D(32,
kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
訓練およびテストデータには,取得した画像にOpenCVでアニメ顔検出を行い,顔領域を切り出したものを使用しました.Tumblrで取得した画像データを訓練,Googleで取得した画像データをテストとして,学習しました.
Epoch 81/1000 128/730 [====>.........................] - ETA: 2s - loss: 0.0728 - acc: 0.9609 256/730 [=========>....................] - ETA: 1s - loss: 0.0667 - acc: 0.9727 384/730 [==============>...............] - ETA: 1s - loss: 0.0610 - acc: 0.9766 512/730 [====================>.........] - ETA: 0s - loss: 0.0636 - acc: 0.9785 640/730 [=========================>....] - ETA: 0s - loss: 0.0629 - acc: 0.9797 730/730 [==============================] - 7s - loss: 0.0611 - acc: 0.9808 - val_loss: 0.4857 - val_acc: 0.8301 Epoch 00080: early stopping
学習結果は,EarlyStoppingを設定して,80回目の試行で切り上げ.テストデータに対して精度0.8となったので,遊び程度ならまあまあ良いかなと思います.本当はもっとデータ増やしたりやCNNを考えて,精度を上げたいところですが.
2. mlmodel へ変換
coremltools を使って,Kerasで学習したモデルをCore MLが読み込めるファイルへと変換します.convertのパラメータ調整もですが,Python2.7系にしか対応していないので,環境作成に時間かかりました.
import coremltools coreml_model = coremltools.converters.keras.convert(h5_path, input_names = 'image', is_bgr = True, image_scale = 0.00392156863, image_input_names = 'image', class_labels = 'labels.txt') coreml_model.save(mlmodel_path)
3. Core MLで識別
流れとしては,AVCaptureSessionでカメラから静止画像を順次受け取って顔画像を切り出して,Core MLで識別の流れです.ほかのブログ等では顔画像の識別はVisionフレームワークを使用してる例が多いですが.この試作アプリではアニメ顔ゆえにOpenCVで行なっています.本当は領域認識もRCNN,YOLOやSSDなどを実装して一緒に推論したいところですが,今回はそこまで手を回せられなかったので
// 予測
func predicate(image: UIImage) {
let image = CIImage(cgImage: image.cgImage!)
let handler = VNImageRequestHandler(ciImage: image)
do {
let model = try VNCoreMLModel(for: self.newGameModel.model)
let req = VNCoreMLRequest(model: model, completionHandler: self.handleClassification)
try handler.perform([req])
} catch {
self.isComputing = false
print(error)
}
}
// 推定結果
private func handleClassification(request: VNRequest, error: Error?) {
guard let observations = request.results as? [VNClassificationObservation] else { fatalError() }
guard let best = observations.first else { fatalError() }
DispatchQueue.main.async {
// 識別した結果に対応する処理など
print("best identifier: " + best.identifier + ", prob: " + String(best.confidence*100))
var str:String = ""
for ob in observations {
str = str + ob.identifier + ", " + String(ob.confidence*100) + "%" + "\n"
}
print(str)
}
}
Core MLでリアルタイム識別を走らせてると,端末が熱くなってくるんですよね.画像一枚ごとに識別するシーンより,時系列データで連続したデータを識別するシーンがこれから多くなると思うので,ちょっと不安になります.近々発表される新型 iPhone はこの計算に耐えられる高スペックのCPUやGPUを積んでくるんでしょうか.楽しみです.


