JavaScript
chrome-extension
Python3
TensorFlow
TensorFlow.js

Ateam Lifestyle x cyma Advent Calendar 2018の17日目は、株式会社エイチームライフスタイルでWebエンジニアをしている@water_resistantが担当します。


はじめに

皆さん機械学習と聞くと何を思い浮かべますか?

おそらく実装するためのサービスやフレームワークを思い浮かべる方が多いかと思います。

Watson、Google AutoML、AWS ML、ChainerやTensorFlowなど機械学習を取り巻く環境は様々です。

この記事ではその中から「TensorFlow.js」という技術に絞ってお話します。

沢山の選択肢から1つの選択肢として考えてもらえるように書きました。

読了後に「面白そうだから、やってみよう」というきっかけになると幸いです。


この記事で対象とするユーザー層


  • 機械学習で何ができるのか体験してみたいと思っている方

  • 機械学習に興味があるが、python等ではなくJavaScriptでできると嬉しいと思う方

  • 機械学習を低スペックなマシンでも実装してみたいと思う方

  • まず何から触っていけば良いのか悩んでいる方


記事の構成



  • 前半


    • 自作Chrome拡張機能「Dehehe」の紹介


      • 「できること」を体験するとイメージが湧きやすいと思ったので作成しました。



    • 面白さを知ってもらうことが目的のパートです。




  • 後半


    • Dehehe」をどうやって作ったのか説明します。

    • 具体的に行うべきことを理解してもらうことが目的のパートです。



前半と後半の2部構成になっております。

前半は機械学習を体験できる内容にしました。

後半はその実装方法など深い内容を書いているので、前半読了後に興味があれば読んでみてください。



【前半】 TensorFlow.jsで何ができるのか体験する

体験してもらうために、TensorFlow.jsが使用されているChrome拡張機能を作りました。

image.png

GitHub Repository: TakeshiOnishi/dehehe


どんな拡張機能か

Google検索結果にいるときに、常時Webカメラが起動します。

その際に、にっこり笑っていないと画面が暗くなり作業ができなくなる拡張機能です。

qiita (1).png

これをクリスマスまで使えば、かなりの笑顔力が身につくでしょう。


拡張機能の利用方法


  1. GitHub Repository: TakeshiOnishi/dehehe
    」から拡張機能をダウンロードしてzipを解凍

  2. Chromeを開きURLに「chrome://extensions」と入力

  3. 右上のデベロッパーモードのチェックをオンにする

  4. 解凍されたフォルダを選択する

(自己責任でお願いします)

※利用情報を収集する処理等は含めておりません。


DEMO

下のgif画像からも明らかなように非常にニッコリしているので効果は明らかですね。

(今回のDEMO動画では弊社新卒のI君が顔出しを快く協力してくれました。 ありがとうございます。)

ver2_conv.gif


仕組み解説

「笑顔」を判定している部分に機械学習モデルを利用しております。

qii2.png

モデルを変更するだけで他にも色々なことができるので、様々な使いみちが考えられますね。


  • 何かしらのユーザー操作をカメラで行えるようにするツール

  • ユーザーの行動を見て、ページ操作に迷っている場合にヘルプを出すツール

  • 渋い顔をしているとチームメンバーSlackに通知が飛ぶツール

また公式サイトでは様々なデモがあるので、よりイメージが湧くと思います。

個人的にはパックマンがおすすめです。



=== 前半と後半の境界 ===

ここからは実装の具体的な話になるので、難易度も上がってきます。

前半部分を見てもっと詳しく知りたいという人であればそのままお進みください。



【後半】 「Dehehe」の実装解説


使う言語・ツール


実装の流れ


  1. 学習済みモデルを取得

  2. 学習済みモデルをTensorFlow.js用に変換

  3. Chrome拡張機能のベースを作成

  4. JavaScriptを記述


    1. 学習モデルをロードする処理

    2. 顔を追跡するトラッキングの準備

    3. 取得された情報をtensor形式へ変換しモデルを呼び出す処理

    4. 判定された結果を元にDOMを書き換える処理




学習済みモデルを取得

学習済みモデルをoarriaga/face_classificationからダウンロードする。

上記モデルは以下のようなレイヤーを持っています。

input_1で64*64の画像を受け取り、推定された結果は7つのカテゴリに分類されて出てくるという実装です。

____________________________________________________________________________________________________

Layer (type) Output Shape Param # Connected to
====================================================================================================
input_1 (InputLayer) (None, 64, 64, 1) 0
____________________________________________________________________________________________________
conv2d_1 (Conv2D) (None, 62, 62, 8) 72 input_1[0][0]
〜〜〜〜〜省略〜〜〜〜〜
____________________________________________________________________________________________________
conv2d_7 (Conv2D) (None, 4, 4, 7) 8071 add_4[0][0]
____________________________________________________________________________________________________
global_average_pooling2d_1 (Glob (None, 7) 0 conv2d_7[0][0]
____________________________________________________________________________________________________
predictions (Activation) (None, 7) 0 global_average_pooling2d_1[0][0]
====================================================================================================
Total params: 58,423
Trainable params: 56,951
Non-trainable params: 1,472

自分で学習させる場合には、下にあるようなCSV形式のデータを利用します。

学習用元データ
データ内容

image.png
image.png

また自分で学習させる際には高スペックPCが要求されますが、Google Colaboratoryを使えば、無料で高性能環境を利用することができます。

Google ColaboratoryのTPUを試してみる | Qiitaで詳しく紹介されています。


学習済みモデルをTensorFlow.js用に変換

ダウンロードした学習モデルはKerasで学習されたモデルなので、そのままではTensorFlow.jsで使用できません。

そのため、tfjs-converterを用いて変換します。

↓ pipで関連モジュールを用意

# 仮想環境作成

# 必要なライブラリをpipでインストール
pip install keras==2.1.5 tensorflow==1.7.0 tensorflowjs==0.1.1

↓ TensorFlow.js用に変換(convert.py)

from keras.models import load_model

import tensorflowjs as tfjs

# TensorFlow.js用にConvert
model = load_model('./fer2013_mini_XCEPTION.110-0.65.hdf5', compile=False)
tfjs.converters.save_keras_model(model, './output/')

outputディレクトリに変換後ファイルが生成されます。

group1-shard1of1

group2-shard1of1
...省略...
group28-shard1of1
group29-shard1of1
model.json

複数ファイル出力されますが、実際にTensorFlow.jsで呼び出す際はmodel.jsonだけです。

というのもmodel.jsonを起点にしてgroupファイルがロードされていくからです。

webpackなどを触ったことがある人は馴染みがある考えかと思います。


Chrome拡張機能のベースを作成

本筋から離れるのと先駆者が大勢居るので、今回は割愛します。

Chromeのオリジナル拡張機能を開発しよう(ソースコードあり)|LIG


JavaScriptを記述

↓ 学習モデルをロードする処理

// ChromeExtensions内部に配置した学習モデルを読み出し

model = await tf.loadModel(chrome.extension.getURL('trained_data/output/model.json'))

↓ 顔を追跡するトラッキングの準備

function initTracker() {

tracker = new tracking.ObjectTracker('face');
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);
tracking.track('#inputVideo', tracker, { camera: true, fps: 4 });
};

↓ 取得された情報をtensor形式へ変換しモデルを呼び出す処理

// 64x64部分は学習済みモデルの入力層の要求データサイズです

let tensor = tf.fromPixels(canvas, 1).resizeNearestNeighbor([64,64]).toFloat();
let offset = tf.scalar(255);
tensor_image = tensor.div(offset).expandDims();

↓ 変換されたデータを使って、モデルから推論する

let prediction = await model.predict(tensor).data();

let result = Array.from(prediction).map(function(p,i){
return {
probability: p,
classNumber: i
};
}).filter(obj => obj.classNumber == SMILE_NUMBER)
.shift()

probability = result.probability

↓ 判定された結果を元にDOMを書き換える処理

// predict(input_video_canvas_tensor); 実行後

if(probability > 0.88) {
// 笑顔度が高いとき
}else if(not_smile_counter++ > 4){
// 連続して笑顔度が低いとき
}


まとめ


  • オフライン環境でも機械学習モデルを使うことができる。

  • 変換は必要だけれど、JavaScriptだけで機械学習モデルを利用することができる。

  • 低スペックのPCでもGoogle Colaboratoryを使えば自分で学習させることもできる。


  • クソアプリ Advent Calendar 2018案件だったかもしれない点は反省。


最後に...

いかがでしたでしょうか。

後半に関してはかなり端折っていた部分も多かったので、分かりづらかったかもしれません。

ただこれをきっかけに「機械学習って面白そうだな」なんて少しでも思ってもらえたら、嬉しいです。

(記述内容に指摘箇所などがあれば、是非コメントください!)

それでは、良い開発ライフを!

Ateam Lifestyle x cyma Advent Calendar 2018、明日は @bayasist に書いてもらう予定です。お楽しみに!


参考リンク


エイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。

https://www.a-tm.co.jp/recruit/