概要
現在、機械学習を勉強しようとしたときに、使用言語の第一候補にはほぼPythonが上がると思います。それほど機械学習 × Pythonは、フレームワークやドキュメント、参考書が充実しています。
では、作成したモデルを実際のアプリケーションでどのように運用すればよいのでしょうか?
考えられるのは、Pythonを実行できるアプリケーションサーバーを用意して、フロントエンドとなるアプリケーションからAPIでデータをやり取りする方法です。しかし、フロントエンドで推測や分類をするたびにサーバーとのやり取りが発生するため、応答速度や費用面でコストがかかります。
フロントエンドだけで、Pythonで作成した機械学習モデルを実行できれば、このようなコストからは解放されます。
本記事では、Kerasで作成したMNIST学習モデル(CNNモデル)を、フロントエンドだけで実行するアプリケーションを作成します。
※ 多少殴り書きですが、ご容赦を。
環境
- windows 10
- VSCode
参考にさせて頂いた記事
参考にした記事です。
今回やりたいことは、この記事で完結しているので、開発の流れなど +α を説明したいと思います。
記事のソースコード
MNIST学習モデルの作成
Python実行環境を構築して、Kerasを使ってMNIST学習モデルの作成します。
※ Kerasとは、機械学習フレームワーク Tensorflowを使いやすしたラッパーフレームワークです。
開発環境構築として、ローカルに構築するパターンと、Colabを使用するパターンの2つを紹介します。
ローカルに構築する
GPUを使用するので、お使いのPCにNVIDIA製のGPUを積んでいるを持っている方が対象です。
上記のmain.py
に記載しているソースは、MNISTのMPLモデルです。より精度の高いCNNモデルは、以下を参照してください。
Colabを使用する
とくにこだわりがなければ、Colaboratoryを使うのがおすすめです。
デフォルトで、tensorflow-gpu、kerasパッケージが導入されていて、GPU実行環境も提供されています。(神)
バージョンに気を使わなきゃいけない環境構築に悩まされないで済みます。
サンプルコード
学習モデルの保存
学習が終わったモデルをmodel.h5として保存します。
model.save('out/model.h5')
学習モデルファイルの変換
Tensorflow.js(JavaScript)でmodel.h5を扱うためには、jsonファイルに変換する必要があります。
変換にも、Pythonを使います。
ローカルで変換を行う場合は、専用の仮想環境を作ったほうがいいです。
Colabでも変換ができるので、model.h5の容量が大きくない場合は、こっちで済ますのが無難です。(サンプルコードに載せてます)
変換を行うと、学習モデルの構造を保存したmodel.jsonと、重みを保存したgroup1-shard1of1.binが出力されます。
重みファイルは、アプリケーション表示時の負荷軽減のために、容量によって自動的に分割されるみたいです。
MNIST学習モデルを React で使用する
フロントエンドアプリケーションは、React(CRA)で作成します。使用言語はTypeScriptです。
コードの詳細は、以下を参考にしてください。
パッケージインストール
以下をインストールします。
npm i @tensorflow/tfjs
MNIST学習モデルの使用手順
変換した学習モデルファイルは、publicフォルダ内に置きます。(ソースコードでは、public/assets/cnn)
推測までの手順は、以下です。
- MNIST学習モデルをロードする
- canvasの手書きデータを28×28pxのグレースケールに変換する
- 変換した画像データをreshape、標準化(0~255 → 0~1)に変換する
- ロードしたモデルインスタンスを使用して推測する
const loadedModel = await tf.loadLayersModel('./assets/cnn/model.json');
/**
* canvasデータを変換する
* @returns 28×28のグレースケール画像データ
*/
const convertImageData = () => {
if (!context) return;
const inputWidth = 28;
const inputHeight = 28;
// resize
const tmpCanvas = document.createElement('canvas').getContext('2d')!;
tmpCanvas.drawImage(context.canvas, 0, 0, inputWidth, inputHeight);
// convert grayscale
let imageData = tmpCanvas.getImageData(0, 0, inputWidth, inputHeight);
for (let i = 0; i < imageData.data.length; i += 4) {
const avg = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3;
imageData.data[i] = imageData.data[i + 1] = imageData.data[i + 2] = avg;
}
return imageData;
};
/**
* 推測
* @param imageData 28×28のグレースケール画像データ
* @returns 結果
*/
const predict = (imageData: ImageData) => {
if (!model) return;
const score = tf.tidy(() => {
// convert to tensor (shape: [width, height, channels])
const channels = 1; // grayscale
let input = tf.browser.fromPixels(imageData, channels).toFloat();
// normalized
input = input.div(tf.scalar(255));
// reshape input format (shape: [batch_size, width, height, channels])
input = input.expandDims();
// predict
return model.predict(input);
});
const result: number[] = [];
const datas = Array.isArray(score) ? score[0].dataSync() : score.dataSync();
datas.forEach(d => result.push(d));
return result;
};
成果物
作成したアプリケーション
ソースコード
まとめ
数年前に機械学習の勉強をしていたときに、モチベーションを保てなくなったのが、「じゃあ、それをアプリケーションとしてどう表現するのか?」という自分の表現力(技術力)の無さでした。
それから時間は少し経ちましたが、フロントエンドを勉強して、このように形にできてひとまずフラストレーションが解消されました。
培ってきた技術が繋がっていくのは楽しいです。
Document