TF.js 実践開発レシピ

TensorFlow.js Layers APIでカスタム画像分類CNNを定義・学習する:Python Kerasとの比較

Tags: TensorFlow.js, Layers API, CNN, 機械学習, ブラウザ学習, Keras

TensorFlow.jsは、WebブラウザやNode.js環境で機械学習モデルの実行や学習を可能にするJavaScriptライブラリです。PythonでTensorFlowやKerasを使って機械学習モデルを開発されている方にとって、TensorFlow.jsのLayers APIは非常に馴染みやすく設計されています。このLayers APIを利用することで、PythonのKerasで行うのと同様のアプローチで、ブラウザやNode.js上で新しいモデルを定義し、データを使って学習させることができます。

本記事では、TensorFlow.jsのLayers APIを用いてカスタムの畳み込みニューラルネットワーク(CNN)モデルを定義し、ブラウザ上で簡単なデータセットを使って学習させる具体的なコード例とその解説を提供します。Python Kerasでのコードと比較しながら説明を進めることで、Pythonでの経験をTensorFlow.jsにスムーズに応用するための手助けとなることを目指します。

TensorFlow.js Layers APIとは

TensorFlow.jsには、モデルの構築やトレーニングを行うための高レベルAPIとしてLayers APIが提供されています。このAPIは、Pythonのtf.keras.layersモジュールやtf.keras.Modelクラスにインスパイアされており、ニューラルネットワークを層(Layer)を積み重ねて構築するという、Kerasと同様の直感的で使いやすい方法を提供します。

Layers APIを使うことで、以下のような操作を容易に行うことができます。

PythonでKerasを使った経験があれば、Layers APIの概念や使い方はすぐに理解できるでしょう。

Python KerasでのカスタムCNN定義例

まず、読者の皆様に馴染みのあるPython Kerasで、簡単な画像分類用のCNNモデルを定義するコードを見てみましょう。

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, InputLayer

# モデルの定義
model = Sequential([
    InputLayer(input_shape=(28, 28, 1)), # 入力層 (例: 28x28画素のグレースケール画像)
    Conv2D(filters=32, kernel_size=3, activation='relu', padding='same'),
    MaxPooling2D(pool_size=2),
    Conv2D(filters=64, kernel_size=3, activation='relu', padding='same'),
    MaxPooling2D(pool_size=2),
    Flatten(),
    Dense(units=128, activation='relu'),
    Dense(units=10, activation='softmax') # 出力層 (例: 10クラス分類)
])

# モデルのコンパイル
model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# モデルのサマリー表示
model.summary()

このコードは、畳み込み層、プーリング層、全結合層を積み重ねた典型的なCNNモデルを定義しています。Sequentialモデルを使用し、addメソッド(ここではリストで渡していますが、model.add()と同等です)を使って層を順に追加しています。最後に、オプティマイザ、損失関数、評価指標を指定してcompileしています。

TensorFlow.js Layers APIでのカスタムCNN定義

それでは、上記のPython Kerasのモデルと同じ構造を持つCNNモデルを、TensorFlow.jsのLayers APIを使って定義してみましょう。

まず、TensorFlow.jsライブラリをインポートします。HTMLの<script>タグで読み込むか、npmでインストールしてimport文を使用します。

// HTMLのScriptタグで読み込む場合
// <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>

// npmでインストールする場合
// npm install @tensorflow/tfjs
// import * as tf from '@tensorflow/tfjs';

Layers APIを使ったモデル定義のコードは以下のようになります。

import * as tf from '@tensorflow/tfjs';

// モデルの定義
const model = tf.sequential(); // Sequentialモデルを作成

// 層の追加
model.add(tf.layers.conv2d({ // 畳み込み層1
  inputShape: [28, 28, 1], // 入力形状 (高さ, 幅, チャンネル)
  filters: 32,
  kernelSize: 3,
  activation: 'relu',
  padding: 'same' // Python Kerasの'same'パディングに対応
}));

model.add(tf.layers.maxPooling2d({ // プーリング層1
  poolSize: 2
}));

model.add(tf.layers.conv2d({ // 畳み込み層2
  filters: 64,
  kernelSize: 3,
  activation: 'relu',
  padding: 'same'
}));

model.add(tf.layers.maxPooling2d({ // プーリング層2
  poolSize: 2
}));

model.add(tf.layers.flatten()); // データを平坦化

model.add(tf.layers.dense({ // 全結合層1
  units: 128,
  activation: 'relu'
}));

model.add(tf.layers.dense({ // 全結合層2 (出力層)
  units: 10, // クラス数
  activation: 'softmax' // 多クラス分類の場合
}));

// モデルのコンパイル
model.compile({
  optimizer: tf.train.adam(), // tf.trainモジュールからオプティマイザを取得
  loss: 'categoricalCrossentropy', // 損失関数 (Pythonのcategorical_crossentropyに対応)
  metrics: ['accuracy'] // 評価指標
});

// モデルのサマリーを表示 (Node.js環境や一部ブラウザ環境のコンソールで確認可能)
model.summary();

Python KerasのコードとTensorFlow.jsのコードを見比べていただくと、その構造が非常に似ていることがわかります。

このように、Python Kerasでのモデル構築の知識があれば、TensorFlow.js Layers APIを使ったモデル定義も直感的に行うことができます。

データの準備

モデルを学習させるためにはデータが必要です。TensorFlow.jsでは、tf.Tensorという形式でデータを扱います。画像データの場合、一般的には [サンプル数, 高さ, 幅, チャンネル数] の形状を持つ4次元テンソルとして準備します。

ここでは、簡単なダミーデータを使って学習の準備をする例を示します。実際には、ImageDataオブジェクトからテンソルを作成したり、tf.data.csvなどの関数を使ってデータをロードしたりします。

import * as tf from '@tensorflow/tfjs';

// ダミーデータの生成 (例: 100枚の28x28グレースケール画像、10クラス分類)
const numSamples = 100;
const imgHeight = 28;
const imgWidth = 28;
const numChannels = 1;
const numClasses = 10;

// 特徴量データ (ランダムな値)
// 形状: [100, 28, 28, 1]
const xTrain = tf.randomNormal([numSamples, imgHeight, imgWidth, numChannels]);

// ラベルデータ (one-hot encoding形式)
// 形状: [100, 10]
// ランダムなクラスIDを生成し、one-hotに変換する例
const labels = tf.randomUniform([numSamples], 0, numClasses, 'int32'); // 0-9のランダムな整数
const yTrain = tf.oneHot(labels, numClasses); // one-hotエンコーディング

// バリデーションデータも同様に準備
const numValidationSamples = 20;
const xVal = tf.randomNormal([numValidationSamples, imgHeight, imgWidth, numChannels]);
const valLabels = tf.randomUniform([numValidationSamples], 0, numClasses, 'int32');
const yVal = tf.oneHot(valLabels, numClasses);

console.log('xTrain shape:', xTrain.shape);
console.log('yTrain shape:', yTrain.shape);
console.log('xVal shape:', xVal.shape);
console.log('yVal shape:', yVal.shape);

// データの解放(不要になったテンソルは解放してメモリを節約することが重要)
xTrain.dispose();
yTrain.dispose();
xVal.dispose();
yVal.dispose();
labels.dispose();
valLabels.dispose();

TensorFlow.jsでは、テンソルはデフォルトでガベージコレクションされません。不要になったテンソルはtensor.dispose()メソッドを使って明示的に解放するか、tf.tidy()を使ってスコープ内のテンソルを自動解放する必要があります。特に学習など大量のテンソルを扱う処理では、メモリ管理が重要になります。

モデルの学習(Fitting)

データの準備ができたら、model.fit()メソッドを使ってモデルを学習させます。これはPython Kerasのmodel.fit()とほぼ同じように動作します。

import * as tf from '@tensorflow/tfjs';

// 前のステップで定義・コンパイルしたmodelと準備したデータ (xTrain, yTrain, xVal, yVal) があるとする

async function trainModel(model, xTrain, yTrain, xVal, yVal) {
  const history = await model.fit(xTrain, yTrain, {
    epochs: 10, // エポック数
    batchSize: 32, // バッチサイズ
    validationData: [xVal, yVal], // バリデーションデータ
    callbacks: tf.callbacks.earlyStopping({ // コールバックの例: 早期終了
      monitor: 'val_loss', // 監視する評価指標
      patience: 3 // 改善が見られないエポック数
    }),
    // 学習の進捗をコンソールに表示
    callbacks: {
      onEpochEnd: (epoch, log) => {
        console.log(`Epoch ${epoch + 1}: loss = ${log.loss.toFixed(4)}, accuracy = ${log.acc.toFixed(4)}, val_loss = ${log.val_loss.toFixed(4)}, val_acc = ${log.val_acc.toFixed(4)}`);
      }
    }
  });

  console.log('学習完了');
  // historyオブジェクトには、エポックごとの損失や評価指標の値が含まれる
  // console.log(history.history);
}

// モデルの定義、コンパイル、データの準備コード (前述のコードをここに記述)
// ...
// ダミーデータを作成し直す例 (メモリ管理のためdisposeも行う)
const numSamples = 100;
const imgHeight = 28;
const imgWidth = 28;
const numChannels = 1;
const numClasses = 10;
const xTrain = tf.randomNormal([numSamples, imgHeight, imgWidth, numChannels]);
const labels = tf.randomUniform([numSamples], 0, numClasses, 'int32');
const yTrain = tf.oneHot(labels, numClasses);
const numValidationSamples = 20;
const xVal = tf.randomNormal([numValidationSamples, imgHeight, imgWidth, numChannels]);
const valLabels = tf.randomUniform([numValidationSamples], 0, numClasses, 'int32');
const yVal = tf.oneHot(valLabels, numClasses);

// モデル定義・コンパイルコード (前述のコードをここに記述)
const model = tf.sequential();
model.add(tf.layers.conv2d({ inputShape: [28, 28, 1], filters: 32, kernelSize: 3, activation: 'relu', padding: 'same' }));
model.add(tf.layers.maxPooling2d({ poolSize: 2 }));
model.add(tf.layers.conv2d({ filters: 64, kernelSize: 3, activation: 'relu', padding: 'same' }));
model.add(tf.layers.maxPooling2d({ poolSize: 2 }));
model.add(tf.layers.flatten());
model.add(tf.layers.dense({ units: 128, activation: 'relu' }));
model.add(tf.layers.dense({ units: 10, activation: 'softmax' }));
model.compile({
  optimizer: tf.train.adam(),
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy']
});

// 学習を実行
trainModel(model, xTrain, yTrain, xVal, yVal).then(() => {
  console.log('トレーニングプロセス終了');
  // 不要になったテンソルやモデルを解放
  xTrain.dispose();
  yTrain.dispose();
  xVal.dispose();
  yVal.dispose();
  labels.dispose();
  valLabels.dispose();
  model.dispose(); // モデル自体もテンソルを保持しているので解放が必要
});

model.fit()は非同期処理であるため、async/awaitを使用するか、Promiseとして扱います。これはJavaScriptでの非同期プログラミングの一般的なパターンです。PythonのKerasとは異なり、学習の進捗表示などもコールバックを使って実装する必要があります。callbacksオプションには、学習中の様々なイベントで実行される関数を指定できます。

Python Kerasとの違い・実践的な注意点

TensorFlow.js Layers APIはPython Kerasに酷似していますが、JavaScript環境特有の違いや注意点があります。

これらの違いを理解しておくことで、よりスムーズに開発を進めることができます。

まとめ

本記事では、TensorFlow.jsのLayers APIを使用して、カスタムの画像分類CNNモデルをJavaScriptで定義し、学習させる方法を解説しました。Python Kerasのコードと比較することで、Layers APIがKerasの概念を忠実に引き継いでおり、Python経験者にとって学習コストが低いことを示しました。

TensorFlow.js Layers APIを使えば、既存のPython Kerasモデルを変換するだけでなく、ブラウザやNode.js環境で直接新しいモデルを構築・実験することも可能です。これにより、ユーザーのデバイス上でのオンライントレーニングや、Python環境なしでのモデル開発といった、新たな可能性が開かれます。

今後は、より複雑なモデルの定義、実際のデータセットを使った学習、モデルの保存・ロード方法の詳細、そしてNode.js環境での学習といったトピックにも触れていくことで、TensorFlow.js Layers APIの活用範囲をさらに広げていくことができるでしょう。

この記事が、Python Kerasの知識を活かしてTensorFlow.jsでのモデル構築・学習に取り組む皆様の一助となれば幸いです。