ネコと犬を区別するKerasモデルをインターネット上で探すと、「ardamavi/Dog-Cat-Classifier」というページが見つかったので、これを使わせてもらうことにします。ページ右端にある[Clone or download]ボタンを使って、ZIPファイルをダウンロードします。
ZIPファイルを展開すると、Dog-Cat-Classifier-masterという名前のフォルダが現れます。この中には、モデルを訓練するPythonコードが書かれたファイルtrain.pyや、モデルの訓練に必要なデータがセットになって含まれています。
train.pyをテキストエディタで開き、34行めのsave_model(model)の下に、次の1行を挿入します。
model.save('cat_dog_model.h5')
[Anaconda Prompt (tfjs)]を起動し、Dog-Cat-Classifier-masterフォルダに移動します。そして、次のコマンドを使って、Python環境での訓練を開始します。
python train.py
すると、[Anaconda Prompt (tfjs)]で次のような訓練経過が表示され、長い時間をかけてモデルが訓練されます。
Epoch 1/25
1259/1259 [==============================] - 37s 30ms/step - loss: 1.4986 - acc: 0.5134 - val_loss: 0.6899 - val_acc: 0.4893
Epoch 2/25
1259/1259 [==============================] - 37s 29ms/step - loss: 0.6954 - acc: 0.5450 - val_loss: 0.7377 - val_acc: 0.5536
Epoch 3/25
1259/1259 [==============================] - 37s 29ms/step - loss: 0.6645 - acc: 0.5961 - val_loss: 0.7586 - val_acc: 0.5821
Epoch 4/25
1259/1259 [==============================] - 37s 29ms/step - loss: 0.6294 - acc: 0.6500 - val_loss: 0.7160 - val_acc: 0.6500
訓練が終わると、Dog-Cat-Classifier-masterフォルダにcat_dog_model.h5という名前のファイルが作成されます。
このH5ファイルを、tensorflowjs converterでTensorFlow.jsモデルに変換します。
、
tensorflowjs_converter --input_format=keras cat_dog_model.h5 model
TensorFlow.jsモデルへの変換に成功すると、Dog-Cat-Classifier-masterフォルダにmodelフォルダが作成されます。中にはmodel.jsonとgroup1-shard1of1ファイルが含まれているので、modelフォルダを、適切なWebサーバーにコピーします。
モデルは次のようなコードで、TensorFlow.jsアプリに読み込むことができます。
const model = await tf.loadModel('https://localhost/dev/9_dog_cat/model/model.json');
下図は、Dog-Cat-Classifier-masterフォルダで提供されているサンプル画像をテストしたところです。
以下は、上図で使用しているJavaScriptコードの抜粋です。
const inputFile = document.getElementById('input-file');
// ページには表示されない<img>要素
const preview = document.querySelector('img');
// [ファイルを選択]ボタンで画像を選択したら
inputFile.addEventListener('change', (e) => {
// 取得したファイル
const imageFile = e.target.files[0];
// ファイルの読み取りに成功したら、readPromise.then()を実行する
new Promise((resolve, reject) => {
const reader = new FileReader();
// ファイルの読み取りに成功したら解決する
reader.onload = (e) => {
resolve(e.target.result);
}
// ファイルを画像として読み取る
reader.readAsDataURL(imageFile);
// 成功したら、<img>要素に画像を割り当てる
}).then((img) => {
// 画像が読み込まれたら
preview.onload = async() => {
// 読み込む画像の幅と高さ用変数
const imageWidth = preview.naturalWidth;
const imageHeight = preview.naturalHeight;
// <canvas>を作成して、それに画像のイメージデータを割り当てる
const canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
const context = canvas.getContext('2d');
// キャンバスに画像を描画する
context.drawImage(preview, 0, 0);
// イメージデータを取得
const imageData = context.getImageData(0, 0, imageWidth, imageHeight);
// キャンバスをページに表示 = 写真が見えるようになる。
document.getElementById('image-container').appendChild(canvas);
// モデルを読み込む
const model = await tf.loadModel('https://localhost/dev/9_dog_cat/model/model.json');
// imageDataを、カラーを保持したまま、tf.Tensorに変換する。
// tf.fromPixels()はtf.Tensor3Dを返す。
const image3d = tf.fromPixels(imageData, 3);
console.log(image3d.shape); // [128, 128, 3]
// 64 x 64のサイズに変更する
const image6464 = tf.image.resizeBilinear(image3d, [64, 64]);
console.log(image6464.shape); // [64, 64, 3]
const imageExpanded = tf.expandDims(image6464);
console.log(imageExpanded.shape); // [1, 64, 64, 3]
const output = model.predict(imageExpanded);
const predictions = Array.from(output.argMax(1).dataSync());
// 0がネコ、1が犬
console.log(predictions);
}
preview.src = img;
});
}, false);