TensorFlow.js による機械学習の高速化: 事前学習済みモデルと Docker の使用

機械学習(ML)と人工知能(AI)の急速に進化する時代において、TensorFlowは洗練されたモデルを開発および実装するための主要なフレームワークとして浮上しています。 TensorFlow の導入により.jsTensorFlow の機能は、JavaScript 開発者向けに強化されています。 

TensorFlow.js は、ML モデルの作成と、ブラウザーまたは Node.js アプリでの即時使用を容易にする JavaScript 機械学習ツールキットです。 TensorFlow.jsは、TensorFlowの機能を実際のWeb開発の領域に拡張しました。 TensorFlow.jsの注目すべき側面は、事前トレーニング済みモデルを利用する機能であり、開発者に幅広い可能性を開きます。 

この記事では、TensorFlow.js と Docker の事前トレーニング済みモデルの概念を探り、潜在的なアプリケーションと利点について詳しく説明します。 

テンソルフローのブログ画像 2400x1260

事前トレーニング済みモデルの理解

事前トレーニング済みモデルは、自分でトレーニングしなくても ML モデルを使用できるため、開発者にとって強力なツールです。 このアプローチは、多くの時間と労力を節約でき、独自のモデルを最初からトレーニングするよりも正確です。

事前トレーニング済みモデルは、大量のデータに対して専門的にトレーニングされた ML モデルです。 これらのモデルは複雑なパターンと表現でトレーニングされているため、特定のタスクを実行するのに非常に効果的で正確です。 開発者は、モデルを最初からトレーニングする必要がなくなるため、事前トレーニング済みのモデルを使用することで、多くの時間とコンピューティング リソースを節約できます。

使用可能な事前トレーニング済みモデルの種類

TensorFlow.js の事前トレーニング済みモデルには、さまざまな潜在的なアプリケーションがあります。 

たとえば、開発者はこれらを使用して次のことができます。

  • 画像内のオブジェクトを識別できる画像分類モデルを構築します。
  • テキストを理解して応答できる自然言語処理 (NLP) モデルを構築します。
  • 音声をテキストに書き起こすことができる音声認識モデルを構築します。
  • ユーザーに製品やサービスを提案できるレコメンデーションシステムを構築します。

テンソルフロー.jsおよび事前トレーニング済みモデル

開発者は、TensorFlow.js を使用して、事前トレーニング済みのモデルを Web アプリケーションに簡単に含めることができます。 TensorFlow.jsを使用すると、モデルのデプロイやトレーニングの専門家でなくても、堅牢な機械学習アルゴリズムの恩恵を受けることができます。 このライブラリには、音声分析、画像識別、自然言語処理など、さまざまな事前トレーニング済みモデルが用意されています(図1)。

視覚、テキスト、音声、身体など、さまざまな種類の事前トレーニング済みモデルの図。
図1: TensorFlow で使用可能な事前トレーニング済みモデルタイプ。

それはどのように機能しますか?

このモジュールを使用すると、TensorFlow SavedModelまたはKeras Model形式でモデルを直接ロードできます。 モデルが読み込まれると、開発者はモデル API で使用できる特定のメソッドを呼び出すことで、その機能を使用できます。図 2 は、トレーニング、配布、および展開に必要な手順を示しています。

事前トレーニング済みモデルのトレーニング、配布、およびデプロイの手順内のデータのフローを示すフロー チャート図。
図2: 事前トレーニング済みの画像分類モデル用の TensorFlow.js モデル API。

訓練

トレーニング セクションでは、機械学習モデルのトレーニングに関連する手順を示します。 最初のステップはデータを収集することです。 その後、このデータは前処理され、クリーニングされ、トレーニング用に準備されます。 その後、データは機械学習アルゴリズムに送られ、機械学習アルゴリズムがモデルをトレーニングします。

  • データの前処理: これは、トレーニング用のデータをクリーニングして準備するプロセスです。 これには、ノイズの除去、エラーの修正、データの正規化などのタスクが含まれます。
  • TFハブ: TF Hub は、事前トレーニング済みの ML モデルのリポジトリです。 これらのモデルは、トレーニング プロセスを高速化したり、モデルの精度を向上させたりするために使用できます。
  • tf.keras: tf.keras は、機械学習モデルを構築およびトレーニングするための高レベルの API です。 これは、機械学習用の低レベルライブラリであるTensorFlowの上に構築されています。
  • 推定: 推定量は、テンソルフローのモデルの一種です。 これは、ML モデルを構築してトレーニングするための簡単な方法です。

流通

配布は、機械学習モデルをユーザーが使用できるようにするプロセスです。 これを行うには、簡単に共有できる形式でモデルをパッケージ化するか、モデルを運用環境にデプロイします。

配布セクションには、機械学習モデルの配布に関連する手順が示されています。 最初の手順では、モデルをパッケージ化します。 これは、モデルが簡単に共有できる形式に変換されることを意味します。 その後、モデルはユーザーに配布され、ユーザーはそれを使用して予測を行うことができます。

配備

デプロイのセクションでは、機械学習モデルのデプロイに関連する手順を示します。 最初のステップは、フレームワークを選択することです。 フレームワークは、機械学習モデルの構築とデプロイを容易にする一連のツールです。 その後、モデルはフレームワークで使用できる形式に変換されます。 その後、モデルは運用環境にデプロイされ、そこで予測を行うことができます。

事前トレーニング済みモデルを使用する利点

TensorFlow にはいくつかの事前トレーニング済みモデルがあり.jsどのプロジェクトでもすぐに利用でき、次の注目すべき利点があります。

  • 時間とリソースの節約: ML モデルをゼロから構築するには、多くの時間とリソースが必要になる場合があります。 開発者はこのフェーズをスキップし、事前トレーニング済みのモデルを使用して、長いトレーニングから既に学習したモデルを使用できます。 その結果、機械学習ソリューションの実装に必要な時間とリソースが大幅に削減されます。
  • 最先端のパフォーマンス: 事前トレーニング済みモデルは通常、膨大なデータセットでトレーニングされ、専門家によって洗練され、さまざまなアプリケーションで最先端のパフォーマンスを提供するモデルが生成されます。 開発者は、これらのモデルをTensorFlowに組み込むことで、これらのモデルの高い精度と信頼性の恩恵を受けることができます.js たとえ彼らが機械学習の深い理解を欠いていても。
  • アクセシビリティ:TensorFlow.jsは、Web開発者にとって事前トレーニング済みのモデルを強力にし、最先端の機械学習機能をプロジェクトにすばやく簡単に統合できるようにします。 このアクセシビリティは、機械学習の機能を利用する最先端のWebベースのソリューションを開発するための新しい機会を生み出します。
  • 転移学習: 事前トレーニング済みモデルは、プロセスの基盤としても機能します。 より小さなドメイン固有のデータセットを使用して、開発者は事前トレーニング済みモデルをさらにトレーニングできます。 転移学習により、モデルは特定のユースケースに迅速に適応できるため、この方法はデータが不足している場合に非常に役立ちます。

TensorFlow .js のコンテナ化が重要なのはなぜですか?

TensorFlow をコンテナー化する.jsは、機械学習アプリケーションの開発とデプロイのプロセスにいくつかの重要な利点をもたらします。 TensorFlow .js のコンテナ化が重要である 5 つの主な理由を次に示します。

  1. Docker は、アプリケーションを実行するための一貫性のある移植可能な環境を提供します。TensorFlow.js をコンテナ化することで、アプリケーション、その依存関係、およびランタイム環境を自己完結型のユニットにパッケージ化できます。 このアプローチにより、コンテナー化された TensorFlow.js アプリケーションを、構成や互換性の問題を最小限に抑えながら、開発マシン、ステージングサーバー、本番クラスターなどのさまざまな環境にデプロイできます。
  1. Docker は TensorFlow.js の依存関係の管理を簡素化します。必要なすべてのライブラリ、パッケージ、および構成をコンテナー内にカプセル化することで、他のシステム依存関係との競合を回避し、アプリケーションが必要な特定のバージョンのライブラリにアクセスできるようにすることができます。 このコンテナ化により、異なるシステムへの依存関係を手動でインストールおよび構成する必要がなくなり、デプロイプロセスがより合理化され、信頼性が高くなります。
  1. Docker は、TensorFlow .js アプリケーションの環境の再現性を保証します。コンテナー内で正確な依存関係、ライブラリ、および構成を定義することで、アプリケーションが異なるデプロイ間で一貫して実行されることを保証できます。
  1. Docker は、TensorFlow.js アプリケーションのシームレスなスケーラビリティを実現します。コンテナーを使用すると、アプリケーションのインスタンスを複数のノードまたはサーバーに簡単にレプリケートおよび分散できるため、大量のユーザー要求を処理できます。
  1. Docker は、アプリケーションとホスト システム間、および同じホスト上で実行されている異なるコンテナー間の分離を提供します。この分離により、アプリケーションの依存関係とランタイム環境がホスト・システムや他のアプリケーションに干渉することがなくなります。 また、依存関係とバージョン管理を簡単に管理できるため、競合が防止され、アプリケーションが動作できるクリーンで分離された環境が確保されます。

完全に機能する ML 顔検出デモアプリの構築

TensorFlow と Docker のパワーを組み合わせることで.js開発者は完全に機能する機械学習 (ML) 顔検出デモ アプリを作成できます。 アプリがデプロイされると、TensorFlow.js モデルはカメラを活用してリアルタイムで顔を認識できます。 ただし、コードを少し変更するだけで、開発者は、ユーザーが画像やビデオをアップロードして検出できるアプリを構築できます。

このチュートリアルでは、TensorFlow.js と Docker を使用して、完全に機能する顔検出デモ アプリを構築する方法を学習します。 図 3 に、このセットアップのファイル・システム・アーキテクチャーを示します。 始めましょう。

前提

このチュートリアルを完了するには、次の主要コンポーネントが不可欠です。

Docker 作成セットアップ用のファイル システム アーキテクチャ (ローカル フォルダー、プレインストールされた tensorflow 依存関係、アプリ フォルダー、ターミナルなど) の図。
図3: Docker Compose 開発セットアップ用のファイル システム アーキテクチャ。

ML 顔検出アプリのデプロイは、次の手順を含む簡単なプロセスです。

  • リポジトリをクローンします。 
  • 必要な構成ファイルをセットアップします。 
  • テンソルフローを初期化します.js。
  • モデルをトレーニングして実行します。 
  • 顔検出アプリを起動します。 

これらの各手順について、以下で説明します。

クイックデモ

急いでいる場合は、次のコマンドを実行して完全なアプリを表示できます。

docker run -p 1234:1234 harshmanvar/face-detection-tensorjs:slim-v1

ブラウザでURLを開きます: http://localhost:1234

代替テキストが必要
図4: ブラウザーで開いた URL。

はじめ

プロジェクトのクローン作成

開始するには、次のコマンドを実行してリポジトリのクローンを作成できます。

https://github.com/dockersamples/face-detection-tensorjs

このデモでは、MediaPipe 顔検出機能のデモを利用しています。 ディテクタを作成するには、 SupportedModelsを含む MediaPipeFaceDetectorモデルの 1 つを から選択します。

例えば:

const model = faceDetection.SupportedModels.MediaPipeFaceDetector;
const detectorConfig = {
  runtime: 'mediapipe', // or 'tfjs'
}
const detector = await faceDetection.createDetector(model, detectorConfig);

次に、検出器を使用して顔を検出できます。

const faces = await detector.estimateFaces(image);

ファイル: インデックス.html:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1.0, user-scalable=no">
  <style>
    body {
      margin: 0;
    }

    #stats {
      position: relative;
      width: 100%;
      height: 80px;
    }

    #main {
      position: relative;
      margin: 0;
    }

    #canvas-wrapper {
      position: relative;
    }
  </style>
</head>

<body>
  <div id="stats"></div>
  <div id="main">
    <div class="container">
      <div class="canvas-wrapper">
        <canvas id="output"></canvas>
        <video id="video" playsinline style="
          -webkit-transform: scaleX(-1);
          transform: scaleX(-1);
          visibility: hidden;
          width: auto;
          height: auto;
          ">
        </video>
      </div>
    </div>
  </div>
  </div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="src/index.js"></script>

</html>

Web アプリケーションの主要なエントリ ポイントはファイルです index.html 。 これには、ユーザーの Web カメラからのリアルタイム ビデオ ストリームを表示するために必要な video 要素と、基本的な HTML ページ構造が含まれています。 顔検出機能に関連する JavaScript スクリプトもインポートされます。

ファイル: src/index.js:

import '@tensorflow/tfjs-backend-webgl';
import '@tensorflow/tfjs-backend-webgpu';

import * as tfjsWasm from '@tensorflow/tfjs-backend-wasm';

tfjsWasm.setWasmPaths(
    `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${
        tfjsWasm.version_wasm}/dist/`);

import * as faceDetection from '@tensorflow-models/face-detection';

import {Camera} from './camera';
import {setupDatGui} from './option_panel';
import {STATE, createDetector} from './shared/params';
import {setupStats} from './shared/stats_panel';
import {setBackendAndEnvFlags} from './shared/util';

let detector, camera, stats;
let startInferenceTime, numInferences = 0;
let inferenceTimeSum = 0, lastPanelUpdate = 0;
let rafId;

async function checkGuiUpdate() {
  if (STATE.isTargetFPSChanged || STATE.isSizeOptionChanged) {
    camera = await Camera.setupCamera(STATE.camera);
    STATE.isTargetFPSChanged = false;
    STATE.isSizeOptionChanged = false;
  }

  if (STATE.isModelChanged || STATE.isFlagChanged || STATE.isBackendChanged) {
    STATE.isModelChanged = true;

    window.cancelAnimationFrame(rafId);

    if (detector != null) {
      detector.dispose();
    }

    if (STATE.isFlagChanged || STATE.isBackendChanged) {
      await setBackendAndEnvFlags(STATE.flags, STATE.backend);
    }

    try {
      detector = await createDetector(STATE.model);
    } catch (error) {
      detector = null;
      alert(error);
    }

    STATE.isFlagChanged = false;
    STATE.isBackendChanged = false;
    STATE.isModelChanged = false;
  }
}

function beginEstimateFaceStats() {
  startInferenceTime = (performance || Date).now();
}

function endEstimateFaceStats() {
  const endInferenceTime = (performance || Date).now();
  inferenceTimeSum += endInferenceTime - startInferenceTime;
  ++numInferences;

  const panelUpdateMilliseconds = 1000;
  if (endInferenceTime - lastPanelUpdate >= panelUpdateMilliseconds) {
    const averageInferenceTime = inferenceTimeSum / numInferences;
    inferenceTimeSum = 0;
    numInferences = 0;
    stats.customFpsPanel.update(
        1000.0 / averageInferenceTime, 120);
    lastPanelUpdate = endInferenceTime;
  }
}

async function renderResult() {
  if (camera.video.readyState < 2) {
    await new Promise((resolve) => {
      camera.video.onloadeddata = () => {
        resolve(video);
      };
    });
  }

  let faces = null;

  if (detector != null) {
  
    beginEstimateFaceStats();

    try {
      faces =
          await detector.estimateFaces(camera.video, {flipHorizontal: false});
    } catch (error) {
      detector.dispose();
      detector = null;
      alert(error);
    }

    endEstimateFaceStats();
  }

  camera.drawCtx();
  if (faces && faces.length > 0 && !STATE.isModelChanged) {
    camera.drawResults(
        faces, STATE.modelConfig.boundingBox, STATE.modelConfig.keypoints);
  }
}

async function renderPrediction() {
  await checkGuiUpdate();

  if (!STATE.isModelChanged) {
    await renderResult();
  }

  rafId = requestAnimationFrame(renderPrediction);
};

async function app() {
  const urlParams = new URLSearchParams(window.location.search);

  await setupDatGui(urlParams);

  stats = setupStats();

  camera = await Camera.setupCamera(STATE.camera);

  await setBackendAndEnvFlags(STATE.flags, STATE.backend);

  detector = await createDetector();

  renderPrediction();
};

app();

顔検出ロジックを実行する JavaScript ファイル。 TensorFlow.js が読み込まれ、事前トレーニング済みの顔識別モデルを使用して、ビデオ ストリームでリアルタイムの顔検出が可能になります。 このファイルは、カメラへのアクセス、ビデオフレームの処理、およびビデオフィードで認識された顔の周囲にバウンディングボックスを作成することを管理します。

ファイル: src/camera.js:

import {VIDEO_SIZE} from './shared/params';
import {drawResults, isMobile} from './shared/util';

export class Camera {
  constructor() {
    this.video = document.getElementById('video');
    this.canvas = document.getElementById('output');
    this.ctx = this.canvas.getContext('2d');
  }
   
  static async setupCamera(cameraParam) {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      throw new Error(
          'Browser API navigator.mediaDevices.getUserMedia not available');
    }

    const {targetFPS, sizeOption} = cameraParam;
    const $size = VIDEO_SIZE[sizeOption];
    const videoConfig = {
      'audio': false,
      'video': {
        facingMode: 'user',
        width: isMobile() ? VIDEO_SIZE['360 X 270'].width : $size.width,
        height: isMobile() ? VIDEO_SIZE['360 X 270'].height : $size.height,
        frameRate: {
          ideal: targetFPS,
        },
      },
    };

    const stream = await navigator.mediaDevices.getUserMedia(videoConfig);

    const camera = new Camera();
    camera.video.srcObject = stream;

    await new Promise((resolve) => {
      camera.video.onloadedmetadata = () => {
        resolve(video);
      };
    });

    camera.video.play();

    const videoWidth = camera.video.videoWidth;
    const videoHeight = camera.video.videoHeight;
    // Must set below two lines, otherwise video element doesn't show.
    camera.video.width = videoWidth;
    camera.video.height = videoHeight;

    camera.canvas.width = videoWidth;
    camera.canvas.height = videoHeight;
    const canvasContainer = document.querySelector('.canvas-wrapper');
    canvasContainer.style = `width: ${videoWidth}px; height: ${videoHeight}px`;
    camera.ctx.translate(camera.video.videoWidth, 0);
    camera.ctx.scale(-1, 1);

    return camera;
  }

  drawCtx() {
    this.ctx.drawImage(
        this.video, 0, 0, this.video.videoWidth, this.video.videoHeight);
  }

  drawResults(faces, boundingBox, keypoints) {
    drawResults(this.ctx, faces, boundingBox, keypoints);
  }
}

カメラの幅、音声、その他の設定関連の項目の設定は、camera.js で管理されます。

ファイル: .babelrc:

この .babelrc ファイルは、JavaScriptコンパイラであるBabelを構成するために使用され、コードのトランスパイル中に適用される変換を定義するプリセットとプラグインを指定します。

ファイル: src/shared:

shared % tree
.
├── option_panel.js
├── params.js
├── stats_panel.js
└── util.js

1 directory, 4 files

フォルダー内にある src/shared パラメーターとその他の共有ファイルは、カメラ、チェック、およびパラメーター値を実行してアクセスするために必要です。 

作成ファイルを使用したサービスの定義

Docker 作成 ファイル内でサービスがどのように表示されるかを次に示します。

services:
  tensorjs:
    #build: .
    image: harshmanvar/face-detection-tensorjs:v2
    ports:
      - 1234:1234
    volumes:
      - ./:/app
      - /app/node_modules
    command: watch

サンプル アプリケーションには、次の部分があります。

  • この tensorjs サービスは、 harshmanvar/face-detection-tensorjs:v2 イメージに基づいています。
  • この画像には、TensorFlow.js を使用して顔検出システムを実行するために必要な依存関係とコードが含まれています。
  • これは、TensorFlow.js と通信するためにポート 1234 を公開します。
  • ボリューム ./:/app ボリューム・マウントをセットアップし、ホスト・マシン上の現在のディレクトリー ( で表される ./) をコンテナー内のディレクトリーにリンク /app します。 これにより、ホスト コンピューターとコンテナーの間でファイルとコードを共有できます。
  • このコマンドは watch 、コンテナー内で実行するコマンドを指定します。 この場合、コマンドを実行し、 watch 顔検出システムが変更または更新を継続的に監視することを示唆します。

イメージのビルド

開発イメージをビルドし、依存関係をインストールして顔検出モデルを起動します。

docker build  -t tensor-development:v1

コンテナの実行

docker run -p 1234:1234 -v $(pwd):/app -v /app/node_modules tensor-development:v1 watch

コンテナサービスの起動

次のコマンドを実行して、アプリケーションを起動できます。

docker compose up -d

次に、コマンドを使用して、 docker compose ps スタックが正しく実行されていることを確認します。 端末は以下の出力を生成します。

docker compose ps
NAME            IMAGE            COMMAND      SERVICE             STATUS                       PORTS
tensorflow    tensorjs:v2     "yarn watch"      tensorjs          Up 48 seconds       0.0.0.0:1234->1234/tcp

Docker ダッシュボードを使用したコンテナーの表示

また、Docker ダッシュボードを利用してコンテナーの ID を表示し、アプリケーション (図 5) コンテナーに簡単にアクセスまたは管理することもできます。

コンテナーの一覧を示す Docker ダッシュボードのスクリーンショット。
図5: Docker ダッシュボードでのコンテナーの表示。

結論

よくやりましたね! TensorFlow.jsのおかげで、JavaScriptを使用して事前にトレーニングされた機械学習モデルをWebアプリケーションに利用するための知識を習得できました。 この記事では、Docker Compose を使用して、1 つの YAML ファイルのみを使用して、完全に機能する ML 顔検出デモ アプリをすばやく作成してデプロイする方法について説明しました。

この新たに発見された専門知識により、このガイドを基盤として、いくつかの追加手順でさらに高度なアプリケーションを構築できるようになりました。 可能性は無限であり、MLの旅はまだ始まったばかりです!

さらに詳しく