TF.js 実践開発レシピ

TensorFlow.jsでローカルファイルやURLから画像認識モデルを安全にロードする:Pythonからの移行者向け

Tags: TensorFlow.js, モデルロード, 画像認識, JavaScript, 非同期処理

TensorFlow.js(TF.js)を用いてWebブラウザやNode.js環境で画像認識AIを動作させるためには、まず学習済みのモデルをメモリ上にロードする必要があります。PythonのTensorFlowやKerasでは、tf.saved_model.loadtf.keras.models.load_model といった関数を使って簡単にモデルをロードできますが、TF.jsではJavaScriptの特性(特に非同期処理)を考慮したロード方法を理解することが重要です。

この記事では、Pythonでの機械学習開発経験を持つ読者の方々に向けて、TF.jsで画像認識モデルをローカルファイルやWeb上のURLから安全かつ効率的にロードするための具体的なコード例と技術解説を提供します。

TF.jsにおけるモデルロードの基本

TF.jsでサポートされているモデル形式は主に以下の2種類です。

Pythonで tensorflowjs_converter ツールを使ってモデルを変換した場合、通常は model.json ファイルと、重みが格納された複数のバイナリファイル(.bin 拡張子)が出力されます。これらのファイルを、TF.jsのロード関数に指定することでモデルをロードします。

ロード処理は非同期で行われます。これはJavaScriptの特徴であり、モデルのダウンロードやファイル読み込みといったI/O処理中にプログラム全体の実行がブロックされないようにするためです。Pythonでのモデルロードが同期的に行われることが多いのとは異なる点です。

Web上のURLからのモデルロード

最も一般的なTF.jsでのモデルロード方法は、Webサーバー上に配置されたモデルファイルをURL経由で取得する方法です。特にブラウザ環境で利用する場合に適しています。

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

// モデルファイル(model.json)のURLを指定
const MODEL_URL = 'https://example.com/path/to/your/model/model.json'; // 実際のURLに置き換えてください

async function loadModelFromUrl() {
  try {
    console.log('モデルをロード中です...');

    // tf.loadLayersModel または tf.loadGraphModel を使用
    // 変換元のPythonモデルがKerasモデルなら loadLayersModel、SavedModelなら loadGraphModel を使うのが一般的です。
    // model.jsonファイルの中身を確認すると、"format": "layers-model" または "format": "graph-model" という記述で形式を判別できます。
    const model = await tf.loadLayersModel(MODEL_URL);

    console.log('モデルのロードに成功しました。');
    // ロードしたモデルを使って推論などの処理を実行
    // const dummyInput = tf.zeros([1, 224, 224, 3]); // 例: 画像入力のダミーテンソル
    // const prediction = model.predict(dummyInput);
    // prediction.print();

    return model;

  } catch (error) {
    console.error('モデルのロードに失敗しました:', error);
    // エラーに応じた処理(ユーザーへの通知など)
    throw error; // エラーを再スローして呼び出し元に通知
  }
}

// 非同期関数を実行
loadModelFromUrl();

認証や追加ヘッダーが必要な場合

場合によっては、モデルファイルが認証保護された場所に置かれていることがあります。その際は、ロードオプションに headers を指定できます。

const MODEL_URL_AUTH = 'https://example.com/path/to/private_model/model.json';

async function loadAuthenticatedModel() {
  try {
    const model = await tf.loadLayersModel(MODEL_URL_AUTH, {
      headers: {
        'Authorization': 'Bearer YOUR_AUTH_TOKEN' // 例: Bearerトークンによる認証
      }
    });
    console.log('認証モデルのロードに成功しました。');
    return model;
  } catch (error) {
    console.error('認証モデルのロードに失敗しました:', error);
    throw error;
  }
}

// loadAuthenticatedModel();

ローカルファイルからのモデルロード

ローカルファイルシステムからモデルをロードする方法は、実行環境によって異なります。

Node.js環境でのファイルシステムからのロード

Node.js環境では、ファイルシステムへのアクセスが可能です。file:// プロトコルを使用してファイルパスを指定します。

import * as tf from '@tensorflow/tfjs-node'; // Node.js環境では -node パッケージを使用
import * as path from 'path';

// モデルファイル(model.json)のローカルパスを指定
const MODEL_PATH = 'file://' + path.resolve('/path/to/your/local/model/model.json'); // 実際のパスに置き換えてください

async function loadModelFromFileSystem() {
  try {
    console.log(`モデルをロード中です: ${MODEL_PATH}`);

    // Node.js環境では tfjs-node パッケージがファイルシステムアクセスをサポート
    const model = await tf.loadLayersModel(MODEL_PATH);

    console.log('モデルのロードに成功しました。');
    // ロードしたモデルを使って推論などの処理を実行

    return model;

  } catch (error) {
    console.error('モデルのロードに失敗しました:', error);
    throw error;
  }
}

// Node.js環境で実行
if (tf.getBackend() === 'tensorflow') { // tfjs-node が有効な場合
    loadModelFromFileSystem();
} else {
    console.warn('Node.js環境ではありません(またはtfjs-nodeが有効ではありません)。ファイルシステムからのロードはできません。');
}

ブラウザ環境でのローカルファイル(ユーザー選択)からのロード

ブラウザはセキュリティ上の制約から、ユーザーが明示的に選択したファイル以外にJavaScriptから直接アクセスすることはできません。したがって、ユーザーにファイルを選択してもらい、その内容を読み込んでTF.jsに渡す必要があります。これは、Webアプリケーションでユーザーがローカルのモデルファイルや重みファイルをアップロードして利用する場合に役立ちます。

HTML:

<input type="file" id="model-file-input" webkitdirectory directory />
<input type="file" id="weights-file-input" multiple />
<button id="load-button" disabled>モデルをロード</button>
<p id="status"></p>

JavaScript:

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

const modelFileInput = document.getElementById('model-file-input');
const weightsFileInput = document.getElementById('weights-file-input');
const loadButton = document.getElementById('load-button');
const statusElement = document.getElementById('status');

let modelJsonFile = null;
const weightsFiles = [];

// model.json ファイルが選択された時の処理
modelFileInput.addEventListener('change', (event) => {
  modelJsonFile = event.target.files[0];
  console.log('model.json が選択されました:', modelJsonFile.name);
  checkFilesSelected();
});

// .bin 重みファイルが選択された時の処理
weightsFileInput.addEventListener('change', (event) => {
  weightsFiles.length = 0; // 配列をクリア
  for (let i = 0; i < event.target.files.length; i++) {
    weightsFiles.push(event.target.files[i]);
  }
  console.log(`${weightsFiles.length}個の重みファイルが選択されました。`);
  checkFilesSelected();
});

// ロードボタンの有効化/無効化をチェック
function checkFilesSelected() {
  if (modelJsonFile && weightsFiles.length > 0) {
    loadButton.disabled = false;
    statusElement.textContent = 'モデルファイルをロード可能です。';
  } else {
    loadButton.disabled = true;
    statusElement.textContent = 'model.jsonと重みファイル(.bin)を選択してください。';
  }
}

// ロードボタンがクリックされた時の処理
loadButton.addEventListener('click', async () => {
  if (!modelJsonFile || weightsFiles.length === 0) {
    statusElement.textContent = 'モデルファイルが不足しています。';
    return;
  }

  statusElement.textContent = 'モデルをロード中です...';
  loadButton.disabled = true; // ロード中はボタンを無効化

  try {
    // ブラウザでローカルファイルからロードする場合、tf.io.browserFiles を使用
    // これは File オブジェクトのマップ({model.jsonのFileオブジェクト, 重み.binのFileオブジェクト...})を期待します。
    const files = [modelJsonFile, ...weightsFiles];
    const model = await tf.loadLayersModel(tf.io.browserFiles(files));

    statusElement.textContent = 'モデルのロードに成功しました。';
    console.log('モデルのロードに成功しました。');

    // ロードしたモデルを使って推論などの処理を実行
    // const dummyInput = tf.zeros([1, 224, 224, 3]); // 例: 画像入力のダミーテンソル
    // const prediction = model.predict(dummyInput);
    // prediction.print();

  } catch (error) {
    statusElement.textContent = `モデルのロードに失敗しました: ${error.message}`;
    console.error('モデルのロードに失敗しました:', error);
  } finally {
    loadButton.disabled = false; // ロード終了後、ボタンを再度有効化
  }
});

// 初期状態をチェック
checkFilesSelected();

Pythonからの移行者へのヒント:非同期処理とファイル構造

Pythonでのモデルロードは通常、ファイルパスを指定するだけで完了します。一方、TF.jsでは非同期処理が中心となるため、await キーワードを適切に使うことが重要です。初めてJavaScriptの非同期処理に触れる場合は、Promiseやasync/awaitの概念を別途学習することをお勧めします。Pythonのasyncioと同様の考え方で理解できる部分が多いです。

また、tensorflowjs_converter で変換されたモデルは、model.json ファイルと複数の .bin ファイルに分割されます。model.json にはモデルの構造や重みファイルへの参照が含まれており、ロード関数にはこの model.json のパス(またはURL)を指定します。.bin ファイルは model.json からの相対パスで指定されているため、ロード時には通常 model.json と同じディレクトリに置かれている必要があります。ローカルファイルからのロード(Node.js)やURLからのロードでは、TF.jsが自動的に .bin ファイルを見つけ出してくれますが、ブラウザで tf.io.browserFiles を使う場合は、model.json と全ての .bin ファイルをユーザーに選択してもらう必要があります。

まとめ

この記事では、TensorFlow.jsを使って画像認識モデルをローカルファイルやWeb上のURLからロードする具体的な方法を解説しました。

モデルをロードできた後は、入力画像(テンソル)を準備し、モデルの predict メソッドを使って推論を実行するステップに進むことができます。ロード処理と同様に、推論処理も通常は非同期で行われます。この記事で紹介したロード方法を基盤として、様々な環境でのTF.jsによる画像認識開発にぜひ挑戦してください。