TensorFlow.jsでのMobileアプリ開発

Deep Learning学習済みモデルを使ったスマホアプリを開発してみました。

なぜTensorFlow.jsを使ったかというと、IDE準備してイチから開発するのは気が遠い話になりそうだったので、HTML5ベースで簡単にアプリ開発ができる「Monaca」というクラウドサービスを使うことにしたから。

1. Monacaについて

Monacaは、有料登録(2000円/月~※2019/08現在)すれば、ローカルIDEで開発したり、サードパーティCordovaプラグインを追加したりできるのですが、フリープランだと、WebベースのIDEで、プロジェクトは3つまで、サードパーティプラグインの登録は不可といった制約が多々あります。

サードパーティCordovaプラグインを登録できないことは、AdmobやMopubといったSDKを用いた広告が使えないことを意味します。ただ、javascriptベースで実装できるnendであれば使えるようです。

開発前から広告のことを考えるのも本末転倒でもあるのですが、少しでもマネタイズできないと継続のモチベーションがなくなってしましますからね。

Monacaへの登録はサイトから簡単にできます。コードのGitHub連携もできますので、GitHubアカウントで登録しておくと良いかと思います。

2. TensorFlow.jsの実装

Monacaでは、アーキテクチャとしては、Node.jsとほぼ同義なので、ローカル環境等でNode.jsで実装したものをほぼそのまま移送可能です。

TensorFlow.jsの実装にあたり、このサイトの実装を参考とさせていただきました。ここでは、PCのWebカメラからリアルタイムにて画像分類モデルにデータを渡していますが、スマホアプリ実装にあたっては、その場で写真撮影したもの、もしくはライブラリから写真を選択して推論させる仕様とします。

全体のコードについてはGitHubにて公開していますので、興味のある方はご参考ください。

2-1. 写真撮影およびライブラリからの写真取得

スマホの写真起動やライブラリ参照の実装コードは以下となります。

Monacaのガイドにサンプル含めて詳細説明がありますので、そちら参照すれば簡単に実装できると思います。

//———————–
// Camera Launch Options
//———————–
function setOptions(srcType) {
var options = {
// Some common settings are 20, 50, and 100
quality: 50,
destinationType: Camera.DestinationType.FILE_URI,
// In this app, dynamically set the picture source, Camera or photo gallery
sourceType: srcType,
encodingType: Camera.EncodingType.JPEG,
mediaType: Camera.MediaType.PICTURE,
allowEdit: true,
correctOrientation: true //Corrects Android orientation quirks
}
return options;
}

function getPicFile() {

var srcType = Camera.PictureSourceType.SAVEDPHOTOALBUM;
var options = setOptions(srcType);
options.targetHeight = 400;
options.targetWidth = 400;
options.destinationType = Camera.DestinationType.DATA_URL;
navigator.camera.getPicture(onSuccess, onFail, options);

//Callback Function on Success
function onSuccess(imageData) {
var image = document.getElementById(‘myImage’);
image.src = “data:image/jpeg;base64,” + imageData;
console.log(“Selected Successfully.”);
$(“#console”).html(<x2>Selected Successfully.</x2>);
$(“#imgText”).empty();
}
//Callback Function on Faild
function onFail(message){
//alert(“Error: No photo has selected.” + message);
}
}

function getPicCamera(){

var srcType = Camera.PictureSourceType.CAMERA;
var options = setOptions(srcType);
options.targetHeight = 400;
options.targetWidth = 400;
options.destinationType = Camera.DestinationType.DATA_URL;
navigator.camera.getPicture(onSuccess, onFail, options);

//Callback Function on Success
function onSuccess(imageData) {
var image = document.getElementById(‘myImage’);
image.src = “data:image/jpeg;base64,” + imageData;
console.log(“Selected Successfully.”);
$(“#console”).html(<x2>Selected Successfully.</x2>);
$(“#imgText”).empty();
}
//Callback Function on Faild
function onFail(message){
//alert(“Error:” + message);
}
}

2-2. 学習済みモデルのロード

学習済みモデルのロードについては、 tf.loadLayersModel関数を用います。TensorFlow.js 1.0以降から、関数がloadModelからLoadLayersModelに変更となっていますのでご注意ください。

モデルは、私がGitHubで公開しているココで生成できるものを用います。

Keras形式でモデル出力させていますので、TensorFlow.jsで扱えるよう変換してやる必要があります。下記コードにてmodel.jsonと重みを保持したバイナリファイルに変換されます。

# Convert to TF.js from Keras
tensorflowjs_converter –input_format keras <Keras Model File>.h5 ./

モデルは、アプリ内に組み込むことも可能ですが、モデルの入れ替えにアプリのアップデートをかけるのは面倒なので、GCP上のWebサーバに公開させる仕様としてみました。

let model;
async function loadModel() {
console.log(“AI model loading..”);
$(“#console”).html(<x2>AI model loading...</x2>);
model=await tf.loadLayersModel(‘https://<Web Server>/model.json’);
console.log(“AI Trained model loaded.”);
$(“#console”).html(<x2>AI Trained model loaded.</x2>);
};

2-3. 推論処理

最後に推論処理です。推論処理は model.predict(tensor_image).data() にて結果を取得することができます。

ただ、推論処理を行う前に、2-1で取得した写真データをモデルのINPUTに合わせてやる必要があります。

function preprocessImage(image){
let tensor = tf.browser.fromPixels(image).resizeNearestNeighbor([64,64]).toFloat();
let offset = tf.scalar(1);
return tensor.div(offset).expandDims();
}

上記の形で、HTML上のimgタグから取得したデータをTensorFlow.jsで使えるテンソルデータの形式に変換できます。tf.scalar(1)としているのは、写真データをそのまま(0~255)で渡していることを意味しています。モデルの学習時に0~1に正規化させている場合は、tf.scalar(255)とすればそのまま応用可能です。

画像データをテンソルに変換し、推論するまでの一連のコードは以下の通りです。

//———————–
// TensorFlow.js method predict tensor
//———————–
async function predict(){

//Get the picture image data
var image = document.getElementById(‘myImage’);
//Transform to tensor data
tensor_image = preprocessImage(image);
prediction = await model.predict(tensor_image).data();
let results = Array.from(prediction)
.map(function(p,i){
return {
probability: Math.round(p*1000)/10,
className: CLASSES[i]
};
}).sort(function(a,b){
return b.probability-a.probability;
}).slice(0,1);
}

3. アプリのビルドおよび公開

完成したアプリのビルドおよびGoogle Playでの公開については後程別記事で記載しようと思います。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする