1. 始める前に
最近、機械学習はかなり話題になっています。その応用範囲は無限大で、近い将来にはほぼすべての業界に影響を与える可能性があります。エンジニアやデザイナーとして、フロントエンドまたはバックエンドで働き、JavaScript に精通している方を対象に、この Codelab は、スキルセットに ML を追加するための入門として作成されました。
前提条件
この Codelab は、JavaScript に精通した経験豊富なエンジニアを対象としています。
作成するアプリの概要
この Codelab では、
- TensorFlow.js を介してウェブブラウザで直接機械学習を使用するウェブページを作成し、ライブ ウェブカメラ ストリームから一般的なオブジェクトを分類して検出します(一度に複数のオブジェクトを検出することもできます)。
- 通常のウェブカメラを強化して、オブジェクトを識別し、検出した各オブジェクトの境界ボックスの座標を取得する
- 次の図のように、検出されたオブジェクトを動画ストリームでハイライト表示します。

動画に人物が映っているかどうかを検出し、特定の時間帯に何人の人物が映っているかをカウントして、そのエリアの混雑状況を推定したり、外出中に犬が家の中の特定の部屋にいることを検出してアラートを送信したりできるとします。これができれば、独自のカスタム ハードウェアを使用して、侵入者(あらゆる種類)を検知したときにアラートを送信する独自のバージョンの Google Nest Cam を作成するのに大きく近づくことになります。なかなか便利です。難しいですか?不正解です。ハッキングを始めましょう。
学習内容
- 事前トレーニング済みの TensorFlow.js モデルを読み込む方法。
- ライブ ウェブカメラ ストリームからデータを取得してキャンバスに描画する方法。
- 画像フレームを分類して、モデルが認識するようにトレーニングされたオブジェクトの境界ボックスを見つける方法。
- モデルから返されたデータを使用して、検出されたオブジェクトをハイライト表示する方法。
この Codelab では、TensorFlow.js の事前トレーニング済みモデルの使用を開始する方法について説明します。TensorFlow.js や機械学習に関連のない概念やコードブロックについては説明しませんが、そのままコピーして貼り付けられるようにしています。
2. TensorFlow.js とは何ですか?

TensorFlow.js は、JavaScript が実行できる場所であればどこでも実行できるオープンソースの ML ライブラリです。これは Python で記述された元の TensorFlow ライブラリに基づいており、このデベロッパー エクスペリエンスと API のセットを JavaScript エコシステムで再作成することを目的としています。
どこで使用できますか?
JavaScript の移植性を考慮すると、1 つの言語で記述し、次のすべてのプラットフォームで簡単に ML を実行できます。
- バニラ JavaScript を使用したウェブブラウザのクライアントサイド
- Node.js を使用したサーバーサイドや Raspberry Pi などの IoT デバイス
- Electron を使用するデスクトップ アプリ
- React Native を使用するネイティブ モバイルアプリ
TensorFlow.js は、これらの各環境内で複数のバックエンドもサポートしています(CPU や WebGL など、実行可能な実際のハードウェア ベースの環境)。このコンテキストの「バックエンド」はサーバーサイド環境を意味するものではありません。たとえば、実行のバックエンドは WebGL のクライアントサイドになる可能性があります。互換性を確保し、高速な実行を維持するためです。現在、TensorFlow.js は以下をサポートしています。
- デバイスのグラフィック カード(GPU)での WebGL 実行 - GPU アクセラレーションを使用して、より大きなモデル(サイズが 3 MB を超えるもの)を実行する最も高速な方法です。
- CPU での Web Assembly(WASM)実行 - たとえば、古い世代の携帯電話など、デバイス全体の CPU パフォーマンスを向上させます。これは、グラフィック プロセッサにコンテンツをアップロードするオーバーヘッドにより、WebGL よりも WASM を使用して CPU で高速に実行できる小規模なモデル(サイズが 3 MB 未満)に適しています。
- CPU 実行 - 他の環境が使用できない場合のフォールバック。3 つの中で最も遅いですが、いつでも利用できます。
注: 実行するデバイスがわかっている場合は、これらのバックエンドのいずれかを強制的に選択できます。指定しない場合は、TensorFlow.js が自動的に選択します。
クライアントサイドのスーパー パワー
クライアント マシン上のウェブブラウザで TensorFlow.js を実行すると、考慮すべきメリットがいくつかあります。
プライバシー
データを第三者のウェブサーバーに送信することなく、クライアント マシンでデータのトレーニングと分類の両方を行うことができます。たとえば、GDPR などの現地の法律を遵守するために、またはユーザーが自分のマシンに保持し、第三者に送信したくないデータを処理するために、この機能が必要になることがあります。
速度
リモート サーバーにデータを送信する必要がないため、推論(データの分類)を高速化できます。さらに、ユーザーがアクセスを許可すれば、カメラ、マイク、GPS、加速度計などのデバイスのセンサーに直接アクセスできます。
リーチとスケーリング
世界中の誰もが、あなたが送ったリンクをクリックしてブラウザでウェブページを開き、あなたが作成したものを利用できます。ML システムを使用するために、CUDA ドライバなどを含む複雑なサーバーサイドの Linux 設定は必要ありません。
費用
サーバーがないため、HTML、CSS、JS、モデルファイルをホストする CDN の料金のみを支払う必要があります。CDN の費用は、サーバー(グラフィック カードが接続されている可能性あり)を 24 時間 365 日稼働させるよりもはるかに安価です。
サーバーサイドの機能
TensorFlow.js の Node.js 実装を活用すると、次の機能が有効になります。
CUDA のフルサポート
サーバー側では、グラフィック カードのアクセラレーションのために、TensorFlow がグラフィック カードで動作するように NVIDIA CUDA ドライバをインストールする必要があります(WebGL を使用するブラウザとは異なり、インストールは不要です)。ただし、CUDA を完全にサポートすることで、グラフィック カードの低レベルの機能を最大限に活用し、トレーニングと推論の時間を短縮できます。どちらも同じ C++ バックエンドを共有しているため、パフォーマンスは Python TensorFlow 実装と同等です。
モデルのサイズ
研究の最先端モデルでは、非常に大規模なモデル(ギガバイト単位のサイズ)を扱うことがあります。これらのモデルは、ブラウザタブあたりのメモリ使用量の制限により、現時点ではウェブブラウザで実行できません。これらの大規模なモデルを実行するには、モデルを効率的に実行するために必要なハードウェア仕様を備えた独自のサーバーで Node.js を使用できます。
IoT
Node.js は Raspberry Pi などの一般的なシングルボード コンピュータでサポートされています。つまり、このようなデバイスで TensorFlow.js モデルを実行することもできます。
速度
Node.js は JavaScript で記述されているため、ジャストインタイム コンパイルのメリットがあります。つまり、Node.js を使用すると、実行時に最適化されるため、パフォーマンスが向上することがよくあります。特に、実行する可能性のある前処理については、パフォーマンスが向上します。この好例は、こちらのケーススタディで確認できます。このケーススタディでは、Hugging Face が Node.js を使用して自然言語処理モデルのパフォーマンスを 2 倍に向上させた方法が紹介されています。
TensorFlow.js の基本、実行場所、メリットについて理解できたので、実際に使ってみましょう。
3. 事前トレーニング済みモデル
TensorFlow.js には、さまざまな事前トレーニング済み ML モデルが用意されています。これらのモデルは TensorFlow.js チームによってトレーニングされ、使いやすいクラスにラップされています。機械学習を始めるには最適な方法です。問題を解決するためにモデルを構築してトレーニングする代わりに、事前トレーニング済みモデルを起点としてインポートできます。
使いやすい事前トレーニング済みモデルのリストは、Tensorflow.js の JavaScript 用モデルのページで確認できます。TensorFlow Hub など、TensorFlow.js で動作する変換済み TensorFlow モデルを取得できる場所もあります。
事前トレーニング済みモデルを使用する理由
一般的な事前トレーニング済みモデルが目的のユースケースに適合する場合、次のようなメリットがあります。
- トレーニング データを自分で収集する必要がない。機械学習システムが学習に使用できるように、データを正しい形式で準備してラベル付けするには、非常に時間と費用がかかる可能性があります。
- コストと時間を削減してアイデアのプロトタイプを迅速に作成できる。
事前トレーニング済みモデルで必要な処理を十分に行える場合は、そのモデルを活用して、モデルから得られた知識をクリエイティブなアイデアの実現に集中して活用できます。 - 最先端の研究の利用。事前トレーニング済みモデルは、多くの場合、一般的な研究に基づいており、このようなモデルに触れるとともに、実際の環境でのパフォーマンスを把握できます。
- 使いやすさと豊富なドキュメント。このようなモデルの人気が高いためです。
- 転移学習 機能。一部の事前トレーニング済みモデルには、転移学習機能が用意されています。これは、ある ML タスクから学習した情報を別の類似した例に転移する手法です。たとえば、元々猫を認識するようにトレーニングされたモデルに新しいトレーニング データを与えると、犬を認識するように再トレーニングできます。空白のキャンバスから始める必要がないため、この方法のほうが速くなります。モデルは、すでに学習した猫の認識方法を使用して、新しいもの(犬)を認識できます。犬にも目と耳があるため、それらの特徴を見つける方法をすでに知っていれば、半分は達成したことになります。独自のデータでモデルをはるかに高速に再トレーニングします。
COCO-SSD とは何ですか?
COCO-SSD は、この Codelab で使用する事前トレーニング済みのオブジェクト検出 ML モデルの名前です。このモデルは、1 つの画像内の複数のオブジェクトをローカライズして識別することを目的としています。つまり、トレーニングで検出するように設定されたオブジェクトの境界ボックスを認識し、そのオブジェクトが指定された画像内のどこにあるかを教えてくれます。次の図に例を示します。

上記の画像に犬が 2 匹以上写っている場合は、2 つの境界ボックスの座標が返され、それぞれの位置が記述されます。COCO-SSD は、人物、車、猫など、90 個の一般的な日常オブジェクトを認識するように事前トレーニングされています。
名前の由来
名前は奇妙に聞こえるかもしれませんが、次の 2 つの頭字語に由来しています。
- COCO: COCO(Common Objects in Context)データセットでトレーニングされたことを指します。このデータセットは、誰でも自由にダウンロードして、独自のモデルのトレーニングに使用できます。このデータセットには、学習に使用できる 20 万枚以上のラベル付き画像が含まれています。
- SSD(Single Shot MultiBox Detection): モデルの実装で使用されたモデル アーキテクチャの一部を指します。この Codelab ではこの点を理解する必要はありませんが、興味がある場合は、こちらで SSD の詳細をご確認ください。
4. セットアップする
必要なもの
- 最新のウェブブラウザ。
- HTML、CSS、JavaScript、Chrome DevTools(コンソール出力の表示)に関する基本的な知識。
コーディングを始めましょう
Glitch.com または Codepen.io で使用できるボイラープレート テンプレートが作成されています。この Codelab では、いずれかのテンプレートをベース状態としてワンクリックでクローンできます。
Glitch で [remix this] ボタンをクリックしてフォークし、編集可能な新しいファイルセットを作成します。
または、Codepen で画面右下の [fork] をクリックします。
この非常にシンプルなスケルトンには、次のファイルが含まれています。
- HTML ページ(index.html)
- スタイルシート(style.css)
- JavaScript コードを記述するファイル(script.js)
便宜上、TensorFlow.js ライブラリの HTML ファイルにインポートが追加されています。たとえば、次のようになります。
index.html
<!-- Import TensorFlow.js library -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>
代替案: お好みのウェブ エディタを使用するか、ローカルで作業する
コードをダウンロードしてローカルで作業する場合や、別のオンライン エディタで作業する場合は、上記の 3 つのファイルを同じディレクトリに作成し、Glitch のボイラープレートから各ファイルにコードをコピーして貼り付けます。
5. HTML スケルトンにデータを入力する
すべてのプロトタイプには、基本的な HTML スキャフォールディングが必要です。これは、後で ML モデルの出力をレンダリングするために使用します。それでは、今すぐ設定しましょう。
- ページのタイトル
- 説明テキスト
- ウェブカメラを有効にするボタン
- ウェブカメラのストリームをレンダリングする動画タグ
これらの機能を設定するには、index.html を開き、既存のコードを次のコードに置き換えます。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Multiple object detection using pre trained model in TensorFlow.js</title>
<meta charset="utf-8">
<!-- Import the webpage's stylesheet -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Multiple object detection using pre trained model in TensorFlow.js</h1>
<p>Wait for the model to load before clicking the button to enable the webcam - at which point it will become visible to use.</p>
<section id="demos" class="invisible">
<p>Hold some objects up close to your webcam to get a real-time classification! When ready click "enable webcam" below and accept access to the webcam when the browser asks (check the top left of your window)</p>
<div id="liveView" class="camView">
<button id="webcamButton">Enable Webcam</button>
<video id="webcam" autoplay muted width="640" height="480"></video>
</div>
</section>
<!-- Import TensorFlow.js library -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>
<!-- Load the coco-ssd model to use to recognize things in images -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"></script>
<!-- Import the page's JavaScript to do some stuff -->
<script src="script.js" defer></script>
</body>
</html>
コードを理解する
追加した重要な点に注目してください。
- ヘッダー用の
<h1>タグといくつかの<p>タグ、およびページの使用方法に関する情報を追加しました。ここでは特別なことはありません。
デモスペースを表すセクションタグも追加しました。
index.html
<section id="demos" class="invisible">
<p>Hold some objects up close to your webcam to get a real-time classification! When ready click "enable webcam" below and accept access to the webcam when the browser asks (check the top left of your window)</p>
<div id="liveView" class="webcam">
<button id="webcamButton">Enable Webcam</button>
<video id="webcam" autoplay width="640" height="480"></video>
</div>
</section>
- 最初は、この
sectionに「invisible」というクラスを指定します。これは、モデルの準備が整い、[ウェブカメラを有効にする] ボタンをクリックしても安全であることをユーザーに視覚的に示すためです。 - ウェブカメラを有効にするボタンを追加しました。このボタンは CSS でスタイル設定します。
- また、ウェブカメラの入力をストリーミングする動画タグも追加しました。これは、まもなく JavaScript コードで設定します。
この時点で出力をプレビューすると、次のようになります。

6. スタイルを追加する
要素のデフォルト
まず、追加した HTML 要素のスタイルを追加して、正しくレンダリングされるようにします。
style.css
body {
font-family: helvetica, arial, sans-serif;
margin: 2em;
color: #3D3D3D;
}
h1 {
font-style: italic;
color: #FF6F00;
}
video {
display: block;
}
section {
opacity: 1;
transition: opacity 500ms ease-in-out;
}
次に、ボタンを非表示にする場合や、モデルの準備がまだできていない場合にデモエリアを使用不可にする場合など、さまざまなユーザー インターフェースの状態に対応できるように、便利な CSS クラスを追加します。
style.css
.removed {
display: none;
}
.invisible {
opacity: 0.2;
}
.camView {
position: relative;
float: left;
width: calc(100% - 20px);
margin: 10px;
cursor: pointer;
}
.camView p {
position: absolute;
padding: 5px;
background-color: rgba(255, 111, 0, 0.85);
color: #FFF;
border: 1px dashed rgba(255, 255, 255, 0.7);
z-index: 2;
font-size: 12px;
}
.highlighter {
background: rgba(0, 255, 0, 0.25);
border: 1px dashed #fff;
z-index: 1;
position: absolute;
}
これで、必要な処理はこれだけです。上記の 2 つのコードでスタイルを正常に上書きすると、ライブプレビューは次のようになります。

デモエリアのテキストとボタンは、HTML にデフォルトでクラス「invisible」が適用されているため、使用できません。モデルを使用する準備が整ったら、JavaScript を使用してこのクラスを削除します。
7. JavaScript のスケルトンを作成する
主要な DOM 要素を参照する
まず、コードで後から操作またはアクセスする必要があるページの主要部分にアクセスできることを確認します。
script.js
const video = document.getElementById('webcam');
const liveView = document.getElementById('liveView');
const demosSection = document.getElementById('demos');
const enableWebcamButton = document.getElementById('webcamButton');
ウェブカメラのサポートを確認する
getUserMedia 経由でウェブカメラ ストリームへのアクセスをサポートしているかどうかを確認する補助関数を追加できるようになりました。
script.js
// Check if webcam access is supported.
function getUserMediaSupported() {
return !!(navigator.mediaDevices &&
navigator.mediaDevices.getUserMedia);
}
// If webcam supported, add event listener to button for when user
// wants to activate it to call enableCam function which we will
// define in the next step.
if (getUserMediaSupported()) {
enableWebcamButton.addEventListener('click', enableCam);
} else {
console.warn('getUserMedia() is not supported by your browser');
}
// Placeholder function for next step. Paste over this in the next step.
function enableCam(event) {
}
ウェブカメラのストリームを取得する
次に、上記のコードをコピーして貼り付け、上で定義した空の enableCam 関数のコードを入力します。
script.js
// Enable the live webcam view and start classification.
function enableCam(event) {
// Only continue if the COCO-SSD has finished loading.
if (!model) {
return;
}
// Hide the button once clicked.
event.target.classList.add('removed');
// getUsermedia parameters to force video but not audio.
const constraints = {
video: true
};
// Activate the webcam stream.
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
video.srcObject = stream;
video.addEventListener('loadeddata', predictWebcam);
});
}
最後に、ウェブカメラが動作するかどうかをテストできるように、一時的なコードを追加します。
次のコードは、モデルが読み込まれたことを想定してカメラボタンを有効にするため、クリックできるようになります。次のステップでこのコードをすべて置き換えるため、すぐに削除できるように準備しておきます。
script.js
// Placeholder function for next step.
function predictWebcam() {
}
// Pretend model has loaded so we can try out the webcam code.
var model = true;
demosSection.classList.remove('invisible');
これで、コードを実行して、現在の状態でボタンをクリックすると、次のような結果が表示されます。

8. ML モデルの使用状況
モデルを読み込む
これで、COCO-SSD モデルを読み込む準備が整いました。
初期化が完了したら、ウェブページのデモエリアとボタンを有効にします(このコードを、前のステップの最後に追加した一時的なコードに貼り付けます)。
script.js
// Store the resulting model in the global scope of our app.
var model = undefined;
// Before we can use COCO-SSD class we must wait for it to finish
// loading. Machine Learning models can be large and take a moment
// to get everything needed to run.
// Note: cocoSsd is an external object loaded from our index.html
// script tag import so ignore any warning in Glitch.
cocoSsd.load().then(function (loadedModel) {
model = loadedModel;
// Show demo section now model is ready to use.
demosSection.classList.remove('invisible');
});
上記のコードを追加してライブビューを更新すると、ページが読み込まれてから数秒後(ネットワーク速度によって異なります)に、モデルを使用できる状態になると [ウェブカメラを有効にする] ボタンが自動的に表示されます。ただし、predictWebcam 関数も貼り付けました。現時点ではコードが何も実行されないため、ここで完全に定義します。
次のステップに進みましょう。
ウェブカメラからのフレームを分類する
次のコードを実行して、ブラウザの準備が整ったときにアプリがウェブカメラ ストリームからフレームを継続的に取得し、分類のためにモデルに渡すようにします。
モデルは結果を解析し、返された座標に <p> タグを描画し、信頼度が一定のレベルを超えている場合はテキストをオブジェクトのラベルに設定します。
script.js
var children = [];
function predictWebcam() {
// Now let's start classifying a frame in the stream.
model.detect(video).then(function (predictions) {
// Remove any highlighting we did previous frame.
for (let i = 0; i < children.length; i++) {
liveView.removeChild(children[i]);
}
children.splice(0);
// Now lets loop through predictions and draw them to the live view if
// they have a high confidence score.
for (let n = 0; n < predictions.length; n++) {
// If we are over 66% sure we are sure we classified it right, draw it!
if (predictions[n].score > 0.66) {
const p = document.createElement('p');
p.innerText = predictions[n].class + ' - with '
+ Math.round(parseFloat(predictions[n].score) * 100)
+ '% confidence.';
p.style = 'margin-left: ' + predictions[n].bbox[0] + 'px; margin-top: '
+ (predictions[n].bbox[1] - 10) + 'px; width: '
+ (predictions[n].bbox[2] - 10) + 'px; top: 0; left: 0;';
const highlighter = document.createElement('div');
highlighter.setAttribute('class', 'highlighter');
highlighter.style = 'left: ' + predictions[n].bbox[0] + 'px; top: '
+ predictions[n].bbox[1] + 'px; width: '
+ predictions[n].bbox[2] + 'px; height: '
+ predictions[n].bbox[3] + 'px;';
liveView.appendChild(highlighter);
liveView.appendChild(p);
children.push(highlighter);
children.push(p);
}
}
// Call this function again to keep predicting when the browser is ready.
window.requestAnimationFrame(predictWebcam);
});
}
この新しいコードで特に重要な呼び出しは model.detect() です。
TensorFlow.js のすべての事前作成モデルには、このような関数(モデルによって名前が異なる場合があるため、詳細についてはドキュメントをご覧ください)があり、実際に機械学習の推論を実行します。
推論とは、入力データを受け取り、機械学習モデル(基本的に多くの数学的演算)で実行して、結果を出力する処理のことです。TensorFlow.js の事前作成済みモデルを使用すると、予測が JSON オブジェクトの形式で返されるため、簡単に使用できます。
この予測関数の詳細については、COCO-SSD モデルの GitHub ドキュメントをご覧ください。この関数は、画像、動画、キャンバスなど、画像のようなオブジェクトをパラメータとして受け取ることができます。このコードを自分で記述する必要がなく、すぐに使用できるため、既製のモデルを使用すると、時間と労力を大幅に節約できます。
このコードを実行すると、次のような画像が表示されます。

最後に、複数のオブジェクトを同時に検出するコードの例を次に示します。

おめでとうございます!このようなものを利用して、古いスマートフォンを Google Nest Cam のようなデバイスに変え、ソファに犬が乗ったときや、カウチに猫が乗ったときにアラートを送信する、といったことが簡単にできるようになることを想像してみてください。コードに問題がある場合は、こちらで最終的な動作バージョンを確認して、コピーした内容に誤りがないか確認してください。
9. 完了
おめでとうございます。これで、TensorFlow.js とウェブブラウザでの機械学習の最初のステップを学ぶことができました。このシンプルなスタートを、クリエイティブなものに変えるのはあなた次第です。何を作りますか?
内容のまとめ
この Codelab では次のことを行いました。
- 他の形式の TensorFlow よりも TensorFlow.js を使用するメリットを学びました。
- 事前トレーニング済み ML モデルから始めることが望ましい状況について学習しました。
- ウェブカメラを使用してオブジェクトをリアルタイムで分類できる、完全に動作するウェブページを作成しました。内容は次のとおりです。
- コンテンツの HTML スケルトンを作成する
- HTML 要素とクラスのスタイルを定義する
- HTML とやり取りしてウェブカメラの有無を検出する JavaScript スキャフォールディングの設定
- 事前トレーニング済みの TensorFlow.js モデルを読み込む
- 読み込んだモデルを使用して、ウェブカメラ ストリームの分類を継続的に行い、画像内のオブジェクトの周囲に境界ボックスを描画します。
次のステップ
作成したものを共有するこの Codelab で作成したものを、他のクリエイティブなユースケースにも簡単に拡張できます。ハッキングが完了した後も、既成概念にとらわれずにハッキングを続けることをおすすめします。
- このモデルが認識できるすべてのオブジェクトを確認し、その知識をどのように活用してアクションを実行できるかを考えてみましょう。今日作成したものを拡張することで、どのようなクリエイティブなアイデアを実現できますか?
(たとえば、選択した特定のオブジェクトを ウェブソケットを使用して検出したときに、別のデバイスに通知を配信するシンプルなサーバーサイド レイヤを追加できます。古いスマートフォンをアップサイクルして、新しい用途を与えるのに最適な方法です。可能性は無限大です。
- ソーシャル メディアで #MadeWithTFJS ハッシュタグを使用すると、作成したプロジェクトが TensorFlow ブログや今後の TensorFlow イベントで取り上げられる可能性があります。