1. 始める前に
ML は昨今、非常に流行っています。用途は制限がないようです。近い将来、ほぼすべての業界で利用されるようになるでしょう。この Codelab は、JavaScript に精通しているエンジニアやデザイナーとして、ML のスキルセットに取り掛かれるよう、フロントエンドまたはバックエンドの開発者向けに作成されています。
前提条件
この Codelab は、JavaScript に詳しい経験豊富なエンジニアを対象としています。
作成するアプリの概要
この Codelab では、
- TensorFlow.js を介してウェブブラウザで直接 ML を使用し、ライブ ウェブカメラ ストリームから一般的なオブジェクトを分類して検出するウェブページを作成します(一度に複数のオブジェクトを可能にします)。
- 通常のウェブカメラを強化してオブジェクトを識別し、検出した各オブジェクトの境界ボックスの座標を取得する
- 次に示すように、動画ストリーム内で見つかったオブジェクトをハイライト表示します。
たとえば、動画に人物が映っているかどうかを検出し、その時間に何人の人がいたかを計算して、特定のエリアの 1 日の混雑状況を推定したり、外出中に家の部屋に犬が検知されたときにアラートを送信したりできると想像してみてください。可能であれば、独自のカスタム ハードウェアを使用して(あらゆるタイプの)侵入者を検知したときにアラートを送信する Google Nest Cam のオリジナル バージョンを作成することをおすすめします。かなりスタイリッシュです。難しいでしょうか?不正解です。さあ、ハッキングをしよう...
学習内容
- 事前トレーニング済みの TensorFlow.js モデルを読み込む方法。
- ライブ ウェブカメラ ストリームからデータを取得してキャンバスに描画する方法
- 画像フレームを分類して、モデルが認識できるようにトレーニングされたオブジェクトの境界ボックスを見つける方法。
- モデルから渡されたデータを使用して、検出されたオブジェクトをハイライト表示する方法。
この Codelab では、TensorFlow.js の事前トレーニング済みモデルの使用を開始する方法に焦点を当てます。TensorFlow.js や ML とは関係のないコンセプトやコードブロックについては説明していませんので、そのままコピーして貼り付けられるようにしています。
2. TensorFlow.js とは
TensorFlow.js は、JavaScript が実行可能な場所であればどこでも実行できるオープンソースの ML ライブラリです。Python で記述された元の TensorFlow ライブラリをベースとし、このデベロッパー エクスペリエンスと JavaScript エコシステム用の API セットを再構築することを目的としています。
使用できる場所
JavaScript のポータビリティにより、1 つの言語で記述して、以下のすべてのプラットフォームで簡単に ML を実行できるようになりました。
- 標準の JavaScript を使用するウェブブラウザのクライアントサイド
- Node.js を使用したサーバーサイドのデバイスや IoT デバイス(Raspberry Pi など)
- Electron を使用したデスクトップ アプリ
- React Native を使用したネイティブ モバイルアプリ
TensorFlow.js は、これらの各環境(CPU や WebGL など、内部で実行できる実際のハードウェアベースの環境)内の複数のバックエンドもサポートしています。「バックエンド」このコンテキストでは、サーバー側の環境を意味するわけではありません。たとえば、実行のバックエンドは WebGL のクライアント側の場合があります)。これは、互換性を確保し、動作の高速化を維持するためです。現在、TensorFlow.js は次のものをサポートしています。
- デバイスのグラフィック カード(GPU)での WebGL の実行 - GPU アクセラレーションを利用して、より大規模なモデル(サイズが 3 MB 超)を実行する最も高速な方法です。
- CPU でのウェブ アセンブリ(WASM)の実行 - 古い世代のスマートフォンなど、さまざまなデバイスの CPU パフォーマンスを向上させます。これは小さいモデル(サイズが 3 MB 未満)に適しています。グラフィック プロセッサにコンテンツをアップロードするオーバーヘッドがあるため、WASM では WebGL よりも CPU での実行速度が速くなります。
- CPU の実行 - 他のどの環境も使用できない場合にフォールバックします。これは 3 つのうち最も遅い方法ですが、常に役立ちます。
注: どのデバイスで実行するかがわかっている場合は、これらのバックエンドのいずれかを強制的に適用するか、指定しない場合は単に TensorFlow.js に処理を任せることもできます。
クライアントサイドの強み
クライアント マシンのウェブブラウザで TensorFlow.js を実行すると、検討に値するいくつかのメリットがあります。
プライバシー
サードパーティのウェブサーバーにデータを送信することなく、クライアント マシン上でデータのトレーニングと分類を行うことができます。GDPR など地域の法律への準拠が求められる場合や、ユーザーが自分のマシンに保存し、第三者に送信してはならないデータを処理する際に必要になることがあります。
速度
データをリモート サーバーに送信する必要がないため、推論(データを分類する作業)を高速化できます。さらに、ユーザーがアクセスを許可すれば、デバイスのセンサー(カメラ、マイク、GPS、加速度計など)に直接アクセスできるようになります。
リーチと規模
世界中の誰もが、送信したリンクをワンクリックでクリックし、ブラウザでウェブページを開き、あなたが作成したものを利用できます。CUDA ドライバを使用した複雑なサーバーサイドの Linux セットアップは不要で、ML システムを使用するだけで十分です。
費用
サーバーがないということは、HTML、CSS、JS、モデルファイルをホストするための CDN さえあれば有料です。CDN の費用は、サーバー(場合によってはグラフィック カードが接続されている)を 24 時間 365 日稼働させるよりもはるかに安価です。
サーバーサイドの機能
TensorFlow.js の Node.js 実装を利用すると、次の機能が有効になります。
CUDA のフルサポート
サーバー側でグラフィック カード アクセラレーションを使用するには、NVIDIA CUDA ドライバをインストールして、TensorFlow がグラフィック カードと連携できるようにする必要があります(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 の基本や実行できる場所とメリットについて理解できたところで、実際に TensorFlow.js を使ってみましょう。
3. 事前トレーニング済みモデル
TensorFlow.js には、さまざまな事前トレーニング済み機械学習(ML)モデルが用意されています。これらのモデルは TensorFlow.js チームによってトレーニングされ、使いやすいクラスにまとめられているので、ML の第一歩を踏み出すのに最適です。問題を解決するためのモデルを構築してトレーニングする代わりに、事前トレーニング済みモデルを出発点としてインポートできます。
Tensorflow.js の JavaScript 用モデルのページでは、使いやすい事前トレーニング済みモデルのリストが随時追加されています。また、TensorFlow Hub など、TensorFlow.js で動作する変換済みの TensorFlow モデルを取得できる場所もあります。
事前トレーニング済みモデルを使用する理由
一般的な事前トレーニング済みモデルから始めると、次のような多くの利点があります。
- トレーニング データを自身で収集する必要がない。正しい形式のデータを準備し、ML システムが学習に使用できるようにラベルを付けると、多くの時間と費用がかかります。
- 費用と時間を削減しながら、アイデアを迅速にプロトタイピングする能力。
「一からやり直す」ことには意味がない事前トレーニング済みモデルで十分にニーズを満たすことができる場合は、モデルから提供される知識を活用して創造的なアイデアを形にすることに集中できます。 - 最先端の研究の活用。多くの場合、事前トレーニング済みモデルは一般的な研究に基づいており、現実世界でのパフォーマンスを理解しながら、そのようなモデルを試すことができます。
- 使いやすさと豊富なドキュメント。このようなモデルの人気が高まりました。
- 転移学習 機能。一部の事前トレーニング済みモデルには転移学習機能が用意されています。転移学習とは、ある ML タスクで学習した情報を別の同様の例に転送するという実質的な手法です。たとえば、最初に猫を認識するようにトレーニングされたモデルに新しいトレーニング データを渡すと、犬を認識するように再トレーニングできます。空白のキャンバスで作業を始めることがなくなるため、処理時間を短縮できます。モデルは、すでに学習した内容を使用して猫を認識し、新しいものを認識できます。結局のところ、犬にも目と耳があるので、すでにそのような特徴の見つけ方を知っているのであれば、そこは半分です。独自のデータではるかに高速な方法でモデルを再トレーニングできます。
COCO-SSD とは
COCO-SSD は、この Codelab で使用する事前トレーニング済みオブジェクト検出 ML モデルの名前です。このモデルは、1 つの画像内の複数のオブジェクトをローカライズして識別することを目的としています。言い換えれば、トレーニングしたオブジェクトの境界ボックスを通知し、提示した画像におけるオブジェクトの位置を知ることができます。以下に例を示します。
上の画像に複数の犬が写っている場合、それぞれの位置を示す 2 つの境界ボックスの座標が与えられます。COCO-SSD は、人、車、猫など、90 の日常的な物体を認識するように事前トレーニングされています。
この名前の由来は何ですか?
この名前は、奇妙に聞こえるかもしれませんが、次の 2 つの頭字語に由来しています。
- COCO: 誰でも無料でダウンロードして独自のモデルをトレーニングする際に使用できる COCO(Common Objects in Context)データセットでトレーニングされたことを指します。このデータセットには、学習に使用できるラベル付き画像が 200,000 枚以上含まれています。
- SSD(シングル ショット マルチボックス検出): モデルの実装に使用されたモデル アーキテクチャの一部。この 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)
HTML ファイルに TensorFlow.js ライブラリのインポートが追加されています。たとえば、次のようになります。
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 スキャフォールディングが必要です。後でこれを使用して、機械学習モデルの出力をレンダリングします。それでは、設定してみましょう。
- ページのタイトル
- 説明文
- ウェブカメラを有効にするボタン
- ウェブカメラのストリーミングを表示する動画タグ
これらの機能を設定するには、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」クラスを指定します。これは、モデルの準備が整った時点でユーザーに視覚的に説明できるようにするためです。[Enable webcam] ボタンをクリックしても安全です。 - 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 用に事前に作成されたモデルには、すべて ML 推論を実行するこのような関数があります(モデルによって名前は異なる場合がありますので、詳細についてはドキュメントをご確認ください)。
推論とは、単純に入力を受け取り、それを ML モデル(基本的には多くの数学演算)で実行し、結果を返す動作です。TensorFlow.js の既製のモデルでは、予測を JSON オブジェクトの形式で返すため、使い方が簡単です。
この予測関数の詳細については、こちらの COCO-SSD モデルの GitHub ドキュメントをご覧ください。この関数はバックグラウンドで大量の処理を行います。つまり、オブジェクト(画像、動画、キャンバスなど)をパラメータとして渡します。あらかじめ用意されたモデルを使用すれば、このコードを自分で記述する必要がなく、すぐに使えるため、多くの時間と労力を節約できます。
このコードを実行すると、次のような画像が表示されます。
最後に、複数のオブジェクトを同時に検出するコードの例を示します。
おめでとうございます!古いスマートフォンを使用して、ソファの上の犬やソファの上の猫を検知したときに通知を受け取ることができる Google Nest Cam のようなデバイスを作るのはどれほど簡単でしょう。コードに問題がある場合は、こちらで最終的な動作バージョンを確認して、誤ってコピーされていないかどうかご確認ください。
9. 完了
これで、ウェブブラウザで TensorFlow.js と ML を使用するための第一歩を踏み出しました。この控えめな始まりをクリエイティブなものに変えるのはあなた次第です。何を作りますか?
内容のまとめ
この Codelab では次のことを行いました。
- 他の形式の TensorFlow よりも TensorFlow.js を使用するメリットについて学びます。
- 事前トレーニング済み ML モデルから始めるべき状況について学びます。
- ウェブカメラを使用してオブジェクトをリアルタイムで分類できる、正常に機能するウェブページを作成しました。以下に例を示します。
- コンテンツの HTML スケルトンを作成する
- HTML 要素とクラスのスタイルを定義する
- HTML を操作し、ウェブカメラの有無を検出するための JavaScript スキャフォールディングをセットアップする
- 事前トレーニング済みの TensorFlow.js モデルを読み込む
- 読み込まれたモデルを使用してウェブカメラ ストリームを連続的に分類し、画像内のオブジェクトを囲む境界ボックスを描画する。
次のステップ
皆様の作品をぜひお聞かせください。この Codelab で作成した内容は、他のクリエイティブ ユースケースにも簡単に拡張できます。読み終わった後も、枠にとらわれずにハッキングを続けることをおすすめします。
- このモデルが認識できるすべてのオブジェクトを確認し、その知識を活用してアクションを実行する方法を考えます。今作成したものを拡張することで、どのようなクリエイティブなアイデアを形にできるか?
(WebSocket を使用して、選択した特定のオブジェクトを検出したときに別のデバイスに通知を送るシンプルなサーバーサイド レイヤを追加することもできます。これは、古いスマートフォンをリサイクルして新しい用途に変えるのに最適な方法です。可能性は無限大)
- ソーシャル メディアで #MadeWithTFJS のタグを付けていただくと、あなたのプロジェクトが TensorFlow ブログで紹介されたり、今後の TensorFlow イベントで紹介されたりするチャンスがあります。