TensorFlow.js学習済みモデルによる推論を実行

2018.10.10

TensorFlow.jsを試す

以前の投稿で、PythonやC言語などで実行可能なTensorFlowのセットアップ手順を紹介しておりますが、今回は、Javascriptで実行するTensorFlow.jsを動かしてみた手順をまとめます。

TensorFlow.js

TensorFlow.jsは、Webブラウザ上で機械学習のモデルの構築、学習、学習済みモデルの実行などが可能になるJavaScriptライブラリです。機械学習の計算にWebGLを介してGPUを利用する事により、計算を高速化する仕組みも持ち合わせています。
TensorFlow.js最大のメリットは、ブラウザで処理を実行できるというところでしょう。
リリース当初は、(KerasやTensorFlowで生成した)既存のモデルを、TensorFlow.jsモデル形式に変換するなど、TensorFlow.js以外の処理を行う必要がありましたが、最近では、学習済みTensorFlow.jsモデルが用意されており、より始めやすくなっていると感じます。
但し、TensorFlow.jsを扱う前提として、そもそもTensorFlowとは何なのか、機械学習やディープランニングの概念などを理解しておく必要があります。

TensorFlowとディープラーニングと機械学習

ここで、TensorFlow及びTensorFlow関連技術について、概略だけ説明しておきます。
ここでの内容は、調べる際に、どんな検索ワードを入力すべきかの参考程度に捉えて、公式ページを初めとしたWebページや、書籍などで理解を深めてください。

TensorFlowは機械学習(マシンラーニング)用ソフトウェアライブラリです。
では、機械学習とは何なのか。
機械学習とは、人間が勉強や経験から学習し、仕事ができる様になるように、コンピュータが自ら学習して、仕事ができる様になる技術です。

機械学習における仕事を推論と呼びます。推論とは、推論データを推論モデルに入力すると、結果を返してくれるプロセスのことです。我々人間が実際に機械学習を利用するとは、このプロセスを利用している事と考えて良いでしょう。

機械学習における学習とは、学習データ(訓練データ、トレーニングデータ)から特徴を抽出し、推論モデルを生成するプロセスのことです。 学習方法(アルゴリズム)は、幾つかあります。ここでは教師あり学習と、教師なし学習について紹介します。また、それぞれの目的についても、示します。

学習方法

学習データ

概要

目的

教師あり学習

入力データ+正解データ

入力データとそれに対する正解データを用意し、
入力データを読み込ませたモデルの出力と正解データ比較し、
誤差を算出。算出結果をモデルにフィードバックして、
モデルを生成する。

分類、回帰

教師なし学習

入力データ

入力データに特徴の抽出や特徴パターンからモデル生成する。

クラスタリング

また、各目的においても、様々なモデル化技法が存在しています。

目的

技法

分類

決定木
単純ベイズ
k近傍法(KNN)
サポートベクターマシーン(SVM)
ニューラルネットワーク(NN)

回帰

決定木
線形回帰
ニューラルネットワーク(NN)

クラスタリング

k-means

ここで、ニューラルネットワーク(NN)という技法が出てきました。
ニューラルネットワークとは、人間の脳神経をモデル化した技法です。その構造は、下図の様に表されます。

そして、このニューラルネットワークの中間層を多層化したものが、ディープラーニング(深層学習)です。
ディープラーニングは、GPUに関する技術向上に伴い、処理速度と処理精度が劇的に飛躍し、注目を集めるようになりました。特に音声・画像・自然言語についての処理が可能です。
そして、このディープラーニングを用いた学習と推論が可能となるソフトウェアライブラリが、TensorFlowです。
尚、ディープラーニングにも、幾つかのネットワークモデルがあり、特に畳み込みニューラルネットワーク(CNN)及び再帰型ニューラルネットワーク(RNN)と呼ばれるネットワークモデルが有名です。
CNNは特に画像処理において主流の技法であり、RNNは時系列データも扱える様にした、音声処理に強い技法と覚えておいて良いと思います。
ここまで出てきた技法の関係性を下図に示します。

本稿では、特に画像処理に特化される為、CNNの概念について理解しておく必要があります。以下、私が理解の助けになったと感じたページを紹介しておきます。

畳み込みニューラルネットワークの仕組み

定番のConvolutional Neural Networkをゼロから理解する

TensorFlow.js学習済みモデルの利用

それでは、TensorFlow.jsを実際に使ってみたいと思います。
今回は学習済みモデルを利用する為、推論のみの実装となります。

TensorFlow.jsのロード

TensorFlow.jsの処理は、Javascriptで記述していきます。
TensorFlow.jsのロードは、以下3つの方法があります。

  • HTMLファイルに記述
  • npmでインストール後、Javascriptに記述
  • npmでインストール後、Node.jsアプリに記述

今回は、フロントエンド実装のみで実現できる様子をより表す為に、HTMLファイルに記述してロードします。
ロード方法の実装サンプルは、最新情報が公式サイトに記載されているので、参照してください。
今回の実装内容については、後述します。

TensorFlow.jsを利用する際の実行環境

TensorFlow.jsは、WebGL(WebAPI)を利用していますので、Webサーバを介して実行する必要があります。
今回は、作業PCローカルで、XAMPPによるApacheサーバを起動した上で、動作確認を行います。
動作確認環境の構成概要図は、以下です。

PoseNetモデル

TensorFlow.jsが公式に公開しているPoseNetモデルを題材にして、手順をまとめます。
PoseNetモデルは、静止画や動画から、人間の姿勢を推定する事ができます。
PoseNetについては、公式GitHubのREADME.mdのほか、公式ブログ投稿では、動作原理についても紹介されています。
公式GitHubには、デモのソースも用意されています。
デモが実際に動くところは、コチラから体験できます。

PoseNetモデルには、以下2つの推論が可能です。

名称

検出内容

Single-Person Pose(以降、SinglePose)

1名検出

Multi-Person Pose(以降、MultiPose)

複数名検出

本稿では、SinglePoseによる1名分の検出を、静止画と動画の両方で試した結果をまとめます。

静止画における推論実行

静止画に対して、推論をかけます。

1. ファイル構成

推論実行におけるファイル構成は以下です。


以下、ディレクトリや各種ファイルの概要です。

index.html

TensorFlow.jsのロード及び、推論結果を表示します。

index.css

Index.htmlの見た目を整えます。

images/

本ディレクトリ直下に、推論対象の静止画を保存しておきます。

image.js

実処理は全てここに記述しています。

2. TensorFlow.js及びPoseNetロード

index.htmlへ、scriptタグで記述します。記述内容は、公式GitHubで紹介されている内容です。

[index.html]</>

3. 推論対象の画像を取得

bodyタグ内では、推論対象の画像を取得し、確認用の表示および、推論結果を上書きして表示する為のcanvas領域を確保します。

[index.html]</>

4. 画像を推論にかける

PoseNetモデルをロードし、画像を推論にかける記述が以下になります。
SinglePoseの推論実行に、estimateSinglePose関数を用います。

[image.js]</>

推論(SinglePose)の引数については、以下の通りです。

_imageElement

推論にかける画像データ
(ImageData|HTMLImageElement|HTMLCanvasElement|
HTMLVideoElemen)

_imageScaleFactor

0.2〜1.0の数値。デフォルトは0.50。
ネットワークを介して画像を供給する前に、画像を拡大縮小する。
この数値を低く設定すると、
画像の縮尺を小さくし、ネットワークに接続するときの速度を上る。

_flipHorizontal

デフォルトはfalse。
ウェブカメラなど、水平に反転されたビデオの場合はtrueに設定し、
ポーズを反転させる。

_outputStride

ストライド(畳み込みの適用間隔)の設定。
デフォルトは16。設定値は32、16、8の何れかを設定すること。
数値が高いほどパフォーマンスは向上するが、精度は低下する。

5. 推論の結果出力

推論の出力は、poseという連想配列にまとめられます。
poseは、下記に示す人間の特徴点をkeypointとし、入力された画像における各keypointの画像中での座標(x,y)及び、keypointである事の確からしさ (score)を含みます。

ID

Part

0

nose

1

leftEye

2

rightEye

3

leftEar

4

rightEar

5

leftShoulder

6

rightShoulder

7

leftElbow

8

rightElbow

9

leftWrist

10

rightWrist

11

leftHip

12

rightHip

13

leftKnee

14

rightKnee

15

leftAnkle

16

rightAnkle

このデータから、入力画像に対して以下を描画し、体制が抽出されている事をビジュアルで示します。

  • keypoint
  • 体の隣り合うkeypointを繋ぐskeltonと呼ぶ人の骨格を表す線

表示結果は、以下の通りです。

これらの描画に便利な関数が、uitlsとして、公式GitHubのデモのソースにまとまっていましたので、抜粋して利用させて頂きました。
以下、簡単に紹介しておきます。

丸の描画

[image.js]</>

keypoint各所に丸を描画

[image.js]</>

skeltonを描画

[image.js]</>

以上の描画関数は、poseを取得した後に呼び出します。

[image.js]</>

推論結果の、総合scoreと、各keypointのscoreは、以下の通りです。
一番先頭のscoreが総合scoreです。あとは、0~16まで各部のscoreが続きます。


※console.log(pose);の出力より抜粋

尚、総合scoreは全身が映ってないと低くなります。
以下より、総合scoreが全keypointのscoreの平均値をとっており、画像からはみ出たkeypointのscoreは0に近づいていることがわかります。


動画における推論実行

動画に対して、推論をかけます。

1. ファイル構成

推論実行におけるファイル構成は以下です。


以下、ディレクトリや各種ファイルの概要です。

index.html

TensorFlow.jsのロード及び、推論結果を表示します。

index.css

Index.htmlの見た目を整えます。

image.js

実処理は全てここに記述しています。

2. TensorFlow.js及びPoseNetロード

ここでの手順については、静止画の時から、変更ありません。

3. 推論対象の画像を取得

動画の場合、推論対象の画像は、内蔵カメラや、外付けのWEBカメラからWebAPIを使ってリアルタイムに取り込みます。
今回は、内臓のフロントカメラを使用しています。

[index.html]</>

video要素にて、onloadedmetadataイベントが発生するまでを、カメラの準備とします。

[video.js] </>

4. 画像を推論にかける

動画を推論にかける際も静止画と同様で、SinglePoseの推論実行に、estimateSinglePose関数を用います。
但し、リアルタイムに更新される動画に、追従して推論実行、推論結果描画を行いたい為、PoseNetモデルのロードと、実際に推論をかける処理を分け、推論処理を再帰的に呼び出します。

PoseNetモデルのロード処理

[video.js] </>

推論実処理

[video.js] </>

5. 推論の結果出力

静止画の時と同様に、keypointとskeltonを動画に描画します。
呼び出しも、静止画の時と同じく、poseを取得した後で行いますが、この時、前回の描画を消さないと、推論開始からのkeypointとskeltonの描画が蓄積していくので、注意します。

[video.js] </>

表示結果は、以下の通りです。

ソースコード

最後に、動作確認に使った、静止画と動画、両方の確認コードを全て以下記載します。
尚、静止画で利用している画像については、フリー素材をお借りしています。各自にて入手ください。

[index.html]</>
[index.css]</>

[image.js]</>

[video.js] </>

まとめ

TensorFlow.jsのPoseNetモデルを使ってみて、使い方次第では、PoseNetモデルをそのまま利用する事も可能かもしれないほどの、正確性がある様に感じました。
少なくとも、全身あるいは上半身の正面がはっきり映っている状態では、PoseNet紹介ページにある画像の様に 、捕捉が可能です。

今回は、SinglePoseのみ試していますが、MultiPoseについても、いずれ試してみたいと思います。