TensorFlow Hub の TensorFlow Lite用モデルを HTML＋JavaScript から使って画像分類（TFJS Task API を利用）

以前、以下の記事にも書いた JavaScript で TensorFlow Lite のモデルを扱える（ブラウザ上で TensorFlow Lite のモデルを使った推論が行える）、TFJS Task API に関する話です。

- [TensorFlow Lite のモデルを Web で扱えるという話についてのざっくりなメモ【Google I/O 2021】 - Qiita](https://qiita.com/youtoy/items/3963f7f2cee431eca835)
- [30行未満の HTML＋JavaScript でカスタムモデルを使った画像分類を試す（TFJS Task API を利用）【Google I/O 2021】 - Qiita](https://qiita.com/youtoy/items/7b42ce2973a457cc5844)

今回の記事の内容をやろうとしたきっかけは以下のツイートのとおりで、自分で作ったモデルのところで [Microsoftさんの Lobe](https://www.lobe.ai/) や [Googleさんの Teachable Machine](https://teachablemachine.withgoogle.com/) で出力したモデルを使おうかと思ったものの、その前により手軽に試せそうな [TensorFlow Hub](https://tfhub.dev/) のトレーニング済みモデルを使ってみる方向を試すのも良いのでは、と思ったことです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">前に試して記事も書いたこちら、自分で作ったカスタムモデルに置きかえてみる、というのもやってみようかな。<br><br>●TensorFlow Lite のモデルを Web で扱えるという話についてのざっくりなメモ【Google I/O 2021】 - Qiita<br>　<a href="https://t.co/W4kpO64AcV">https://t.co/W4kpO64AcV</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1411127157288439808?ref_src=twsrc%5Etfw">July 3, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## TFJS Task API について
TFJS Task API に関する説明については、冒頭にも書いた過去の 2つの記事に書いてあるので、ここでは省略します。

## TensorFlow Hub について
[TensorFlow Hub は、公式の説明にあるとおり「トレーニング済み機械学習モデルのリポジトリ」](https://www.tensorflow.org/hub?hl=ja)です。

今回利用する画像を対象にしたモデル以外にも、音・動画・テキストを対象にしたものもあります。
![TensorFlow Hubのモデル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/11a38c06-79bc-f24f-a9a3-408e72e6c85c.jpeg)
![Problem Domains](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6672c72a-40c1-3875-27a0-93c9420d135d.jpeg)

## 画像分類を試す
### TensorFlow Hub から画像分類用モデルを持ってくる
それでは、TensorFlow Hub で画像分類用モデルをいくつかピックアップしてみます。

#### 表示されるモデルを絞りこむ
[デフォルト設定だと、様々なモデルが表示される](https://tfhub.dev/)ので、フィルタを設定していきます。
まずは、Quick Links の中の「All Models」を選んで、トレーニング済みモデルが表示されるようにします。
![QuickLinksの選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2c4c0541-62a3-681c-4182-8062e4da0b33.jpeg)

[その後の画面](https://tfhub.dev/s?subtype=module,placeholder)では、Problem domain の中を少し下にスライドしていって「Image の中の Classification」を選んで、表示されるモデルを画像分類用のものに限定します。
![Problem Domains.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/eb2af8b1-42e3-6d65-0637-b2bd00f4d740.jpeg)

[さらにフィルタが適用された画面](https://tfhub.dev/s?module-type=image-classification&subtype=module,placeholder)で、Model format の中の「TFLite（TensorFlow Lite）」を選択します。
![ModelFormat.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/45738ec4-b9df-aa1c-e946-1e521a3a3b1c.jpeg)

これで、[TensorFlow Lite用のトレーニング済みモデル（画像分類用）](https://tfhub.dev/s?deployment-format=lite&module-type=image-classification&subtype=module,placeholder)が表示される状態になりました。

#### 表示されたモデルから試すものを選ぶ
まずは、表示されたトップに出ていた[「efficientnet/lite0/classification」](https://tfhub.dev/tensorflow/lite-model/efficientnet/lite0/int8/2)の「TFLite (efficientnet/lite0/fp32)」・「TFLite (efficientnet/lite0/int8)」・「TFLite (efficientnet/lite0/uint8)」の 3つを一通りダウンロードしてみました。

モデルの説明として「EfficientNet-Lite models, trained on Imagenet (ILSVRC-2012-CLS), optimized for TFLite, designed for performance on mobile CPU, GPU, and EdgeTPU.」と書かれたものです。
大まかな内容としては、「TensorFlow Lite用に最適化する形で、ImageNet をデータセットとして学習を行った EfficientNet-Lite のモデル」となるかと思います。

最初は「TFLite (efficientnet/lite0/int8)」で動いたのを確認してから、他2つも試してみる、という流れで進めました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">TensorFlow Hub のこのモデルの TensorFlow Lite用の出力、int8 だけでなく fp32・uint8 も試したけど、特に問題なく動いているっぽい。 <a href="https://t.co/qbu13miJfw">https://t.co/qbu13miJfw</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1411136960572231685?ref_src=twsrc%5Etfw">July 3, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ちなみに、「EfficientNet-Lite」は、以下の TensorFlow　のブログにも出ているように、モバイル向けを意識した EfficientNet の軽量版モデル（処理負荷が抑えられるように調整されているっぽい）です。
　●Higher accuracy on vision models with EfficientNet-Lite — The TensorFlow Blog
　　https://blog.tensorflow.org/2020/03/higher-accuracy-on-vision-models-with-efficientnet-lite.html?linkId=84432329
上記の記事内の比較データで、同じくモバイル向けを意識した MobileNet の V2 との比較なども出ています。

自分は、過去にスマホ向けの TensorFlow Lite用モデルを出力するのに「TensorFlow Lite Model Maker」という仕組みを使ったことがあったのですが、その仕組みの中の転移学習のデフォルト設定で指定されていたモデルとして見かけていました。
　●TensorFlow Lite Model Maker による転移学習の過程で accuracy・loss を可視化（グラフ化）する - Qiita
　　https://qiita.com/youtoy/items/4f198afb3254613efc75

今回は、さらにもう1つ[「imagenet/mobilenet_v3_small_100_224/classification」](https://tfhub.dev/google/imagenet/mobilenet_v3_small_100_224/classification/5)の「TFLite (v5, metadata)」を試しました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">TFJS Task API のお試し、次は TensorFlow Hub の<br>「Imagenet でトレーニングされた、MobileNet V3 small (depth multiplier 1.00)」を試してみよう。 <a href="https://t.co/KPOr8UNrMF">pic.twitter.com/KPOr8UNrMF</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1411138548263133187?ref_src=twsrc%5Etfw">July 3, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### TFJS Task API を使ったプログラム
それでは、上記のモデルを呼び出して画像分類を行うプログラムの話にうつっていきます。

#### ローカルのサーバーをたてる
今回、TensorFlow Hub からダウンロードした画像分類用のモデルをローカルに置いて、HTML＋JavaScript で作ったプログラムから呼び出す形で試そうと思います。
その際、ローカルのファイルを呼び出すためにはサーバーを立てる必要があるので、その対応をします。

とはいっても、Python を使ったワンライナーで簡易にサーバーをたてるだけです。
以下の記事にもあるワンライナーを使って、今回の内容では「http://localhost:8000/」で HTMLファイルにアクセスできるようにしています。
　●ワンライナーWebサーバを集めてみた - Qiita
　　https://qiita.com/sudahiroshi/items/e74d61d939f18779970d

#### HTML＋JavaScript を準備して実行
プログラムは、[以前の Qiitaの記事](https://qiita.com/youtoy/items/7b42ce2973a457cc5844)を書いた時に公式サンプルの中身をガリガリ削って、最小限の部分を残したものに、少しだけ手を加える形にします。

内容はシンプルで[以前の記事](https://qiita.com/youtoy/items/7b42ce2973a457cc5844)でも触れた内容なので、ここでは中身だけ掲載します。
以前の記事と異なる部分は「モデルを呼び出す部分の URL」と、「画像分類結果として出力する数（以前はトップの 1つだけ、今回は上位3つを指定）・コンソールへの出力処理（画像分類の上位3位の結果として得られる内容は、ページ内表示でなくコンソール出力に)」です。

```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>TFJS Task API - Image Classification</title>
</head>
<body>
  <div class="container">
    <img id="img" src="https://storage.googleapis.com/tfweb/demos/static/wine.jpeg" crossorigin="anonymous" width="400">
    <button id="button">推論を実行</button>
    <div id="result"></div>
  </div>
  <script src='https://cdn.jsdelivr.net/npm/@tensorflow-models/tasks@0.0.1-alpha.8'></script>
  <script type="text/javascript">
    // 参照元： TFJS Task API - Image Classification
    //      https://codepen.io/jinjingforever/pen/VwPOePq

    document.getElementById('button').addEventListener('click', async () => {
      const model = await tfTask.ImageClassification.CustomModel.TFLite.load({
        // model: 'https://storage.googleapis.com/tfweb/models/mobilenet_v2_1.0_224_1_metadata_1.tflite',
        // model: 'http://localhost:8000/efficientnet_lite0_fp32_2.tflite',
        // model: 'http://localhost:8000/lite-model_efficientnet_lite0_uint8_2.tflite',
        // model: 'http://localhost:8000/efficientnet_lite0_int8_2.tflite',
        model: 'http://localhost:8000/lite-model_imagenet_mobilenet_v3_small_100_224_classification_5_metadata_1.tflite',
        maxResults: 3,
        // maxResults: 1,
      });
      const result = await model.predict(document.getElementById('img'));
      const resultEle = document.getElementById('result');
      resultEle.textContent = `${result.classes[0].className} (${result.classes[0].score.toFixed(3)}).`;
      console.log(result.classes);
    });
  </script>
</body>
</html>
```

上記で呼び出している画像は、[公式サンプルのプログラム](https://codepen.io/jinjingforever/pen/VwPOePq)でもオンラインから呼び出されていた画像です。
また上記では、変更前の内容やモデル切り替え用の URL といった部分をコメントアウトして残しています。

プログラムを実行した結果の、結果表示後のページとコンソールの出力は以下のとおりです（モデルは「imagenet/mobilenet_v3_small_100_224/classification」を指定）。
![画像分類の実行結果.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/de51e1cb-e69d-5797-080b-99a7210f05e4.jpeg)
ページ内にもコンソール出力にも、結果が表示されているのが確認できました。

## おわりに
今回、TensorFlow Hub の TensorFlow Lite用モデルをいくつか選び、それを TFJS Task API を利用したプログラムから利用してみました。
そして、画像分類が短いコードで問題なく動かせることを確認しました。

冒頭にも書いたとおり、この後は以下のツイートにも書いていた Teachable Machine や Lobe で出力したモデルを使えるか試してみようと思います。
（また、記事の途中で話題に出していた「TensorFlow Lite Model Maker」との組み合わせも試してみたいところです）

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">とりあえず、Googleさんの <a href="https://twitter.com/hashtag/TeachableMachine?src=hash&amp;ref_src=twsrc%5Etfw">#TeachableMachine</a> と、Microsoftさんの <a href="https://twitter.com/hashtag/Lobe?src=hash&amp;ref_src=twsrc%5Etfw">#Lobe</a> あたりで、TensorFlow Lite用モデルを作って、JavaScript から呼び出す、<br>というのをやってみようかな。 <a href="https://t.co/e20zSVvymc">https://t.co/e20zSVvymc</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1411127831338258434?ref_src=twsrc%5Etfw">July 3, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>