今度はTeachable Machineで「あったらいいな♪」をかなえてみる

こんにちは！こんばんは
地方で商業施設を管理するtsumeです。

前回`Glide`を使って味を占めたので、またまたスマホを仕事用便利ツールに改造しようと目論みました。
今回は備品管理のお助けツールとして機械学習（以下ML）ツールである`Teachable Machine`に目を付けました。

前回`Glide`を使って業務改善にトライしてみたお話

https://qiita.com/M8nEl0s0v8/items/2ded7f1299f00c2e7f1e

# 新たに思いついたこと

商業施設では、常にさまざまな備品を管理、使用しています。
例えばソファやテーブルなどの家具です。
広い館内でこれらを管理するのはなかなか骨が折れるもので。。

+ 広い館内でどこに・なにが・どれだけ存在するかの把握が大変
+ イベントや館内状況により、備品の配置が知らないうちによく変わる
+ 使用した後に正しい場所へ戻されない（保管場所を忘れがち）
+ 整理整頓がモットーなtsumeにとって鬼ストレス👹

といった具合です。

**備品をカメラに映したら、個数・保管場所を教えてくれる機能をスマホに持たせたい！**

# 使用ツール
+ `Teachable Machine`
+ `CodePen`
+ `ChatGPT`(GPT-4o.)

**全体像**
①`Teachable Machine`で備品の画像を撮影する
②撮影した画像をAIに学習させ、画像識別モデルを作成する
③`CodePen`へできあがったモデルのURLを実装する
④`ChatGPT`を使用してHTML・JSコードを生成し、スマホで実用できる仕様に調整する
⑤`CodePen`をスマホで使用し、備品を識別する

:::note warn
今回は`CodePen`で識別結果が確認できることをゴールとしました。
:::

:::note info
`CodePen`を選んだ理由
+ Googleとのアカウント連携ですぐに使用できる
+ UIがシンプルで初心者でも使用しやすい
+ エラー箇所を表示してくれるのでデバッグがしやすい
+ コーディングからスマホでの使用まで`CodePen`一つで完結できる
:::


# 完成品
https://x.com/M8nEl0s0v8/status/1828615229003251949

# 制作過程
### １.Teachable Machineで学習させたいことを選ぶ
備品の形状をもとに備品を識別するため、`Teachable Machine`に画像データを学習させていきます。

`Teachable Machine`のUIはシンプルです。
画像、音声、ポーズの３種類から`プロジェクト`を選択できます。
![Teachable Machine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/a3262925-641b-e3f4-cbe8-a6787ad8e8d0.png)

### ２.学習させてみる
画像の学習モデルは、あらかじめ学習した画像データを基に識別を行うため、識別させたい備品の数だけクラス（備品の種類）を作成していきます。

画像データについて今回は、PCの内カメラで読み込ませやすいように、あらかじめ撮影・プリントアウトしておいた写真を使用しました（それぞれ数種類の角度を用意）。

`Class`:備品の名称を入力します
`ウェブカメラ`：画像を内カメラで連写しアップロードします
`アップロード`：フォルダにある画像からアップロードします

![クラス作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/81960727-241f-97e8-10d3-c389753a968d.png)

備品の名称・保管場所・在庫を知りたいので、`名称_保管場所：〇〇（在庫）`という形で、４つクラスを作成しました。１つ以上クラスを作成すると、次のステップである`モデルをトレーニングする`が可能になります。
![クラス作成後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/4edf8ddb-afb6-0bf2-9440-c1eafe991774.png)

:::note warn
`Class`は最初の設定が肝心！
ここで時間を使ってしまった点が一つ。`Class`で設定した名称（ラベル）は、後に別のwebサービスと連携してから変更しても反映されない模様。。`CodePen`を使用した場合は、連携後に名称変更・再度読み込みしても反映されず、結局モデルを作り直す羽目になりました（URLに紐づいているから？）。
:::

学習中。。。🤖
![トレーニング中.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/2e983f3c-bfdc-04db-8393-63a4faf66c6d.png)

### ３.学習できた！
学習が完了すると、次のステップである`プレビュー`で結果が確認できます。カメラに映った長机をしっかり識別できています。要領がよくてうらやましい。。
![学習した.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/c10d928f-25ed-3dae-c463-bbe480db173f.png)

`モデルをエクスポートする`からアップロードを行うと、共有リンクとコードが発行されます。ここでそれぞれをコピーしておきます。
![アップロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/413afe36-c11d-816e-0072-792332caacb8.png)

### 4.CodePenを開く
できあがったモデルを実際に使えるようにするため、`CodePen`へ連携します。新たに作成する場合は`Pen`を選択し、コーディングをしてきます。
![CodePen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/0274faf0-a009-44b6-c31f-1118f7d6cefc.png)

:::note info
参考にできるペンが豊富
`CodePen`は他のユーザが作成したコードも公開されています。`Search CodePen`で検索し、コードの書き方を参考にすることができます。また、`Add to Pins`でピン留めすることもできます。
:::

`CodePen`のペンは３つの領域で構成されています。
<dl>
  <dt> HTML </dt>
  <dd>「骨組み」を作るための言語です。文章や画像、リンクなどの要素をページ内へ配置するために使います。</dd>
  <dt>CSS</dt>
  <dd>「骨組み」に「皮膚」をつけるための言語です。色やフォント、レイアウトやサイズなど、見た目を整えるために使います。</dd>
  <dt>JS　(JavaScript)</dt>
  <dd>実際に「動き」や「機能」を加えるための言語です。操作に応じてページを変化させたり、動作を実行させるために使います。</dd>
</dl>

画像左上の`Untitled`は、ペンの名称を入力し保存します。

![Pen_introduction.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/2927219b-c75c-0a55-af9a-44249d16a3f2.png)

### ５.CodePenへ実装してみる
ここからは`ChatGPT`に活躍してもらいます。いずれのコードも`ChatGPT`に生成してもらい、各領域にコピペしていきます。
![スクリーンショット 2024-08-26 123950.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/71636afe-aefc-44a2-dd2a-0b5e99b5d339.png)
![スクリーンショット 2024-08-24 135325.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/4e8eee8c-8068-4641-a258-e0cdba46393c.png)
![スクリーンショット 2024-08-24 135419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/c1916bb8-8d73-057c-1d78-e774c3f0d457.png)
すぐに会議イスや丸テーブルを識別して結果を返すことができました！

### ６.実用レべルに仕上げる
モデルを基に識別することができましたが、一つ重要な問題が。。
それは **「内カメラで実用できるのか」** というところにあります。
`Teachable Machine`では内カメラを使用してモデルを作成しているため、プロンプトを工夫しないと`ChatGPT`は内カメラで機能するコードを生成します。


<details><summary>　最終的なコードはコチラ　</summary>

```ruby:HTMLコード

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトル</title>
    <script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
</head>
<body>
    <h1>見出し</h1>
    <video id="webcam" autoplay playsinline width="430" height="320"></video>
    <p id="result">Loading model...</p>
</body>
</html>

```

```ruby:外カメラを機能させるJSコード

let classifier;
let video;
const modelURL = 'Teachable MachineのモデルURL';

// Load the Teachable Machine model
async function loadModel() {
    classifier = await ml5.imageClassifier(modelURL + 'model.json');
    document.getElementById('result').innerText = 'Model loaded';
}

// Setup the webcam with the rear camera
async function setupWebcam() {
    video = document.getElementById('webcam');
    try {
        const stream = await navigator.mediaDevices.getUserMedia({ 
            video: { facingMode: { exact: 'environment' } } // Use the rear camera
        });
        video.srcObject = stream;
    } catch (err) {
        console.error('Error accessing the webcam:', err);
    }
}

// Make a classification
async function classifyVideo() {
    const results = await classifier.classify(video);
    document.getElementById('result').innerText = `Label: ${results[0].label} Confidence: ${results[0].confidence.toFixed(4)}`;
    
    // Send the classification result using Axios
    axios.post('https://your-server-endpoint.com/classification', {
        label: results[0].label,
        confidence: results[0].confidence
    }).then(response => {
        console.log('Result sent successfully:', response.data);
    }).catch(error => {
        console.error('Error sending result:', error);
    });

    // Repeat classification
    classifyVideo();
}

// Initialize everything
async function init() {
    await setupWebcam();
    await loadModel();
    classifyVideo();
}

// Start the process
window.onload = init;
```

</details>

<details><summary>　上記のプロンプト　</summary>

数回の思考錯誤の末、「最初に生成したJSコードを原型に外カメラで分類」という条件を追加したプロンプトが正しい道を示してくれました。
![外カメラで機能するように指示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/8bfab6fa-3679-94da-df01-f9fb14742b41.png)

</details>

<details><summary>　苦労エピソード　</summary>

最終的にイメージ通りの働きをするJSコードを導くことができましたが、今回も`ChatGPT`の出力揺れやハルシネーションに少し付き合う結果となりました。

- [x] 外カメラが機能するが、識別モデルが表示されない

- [x] 外カメラが機能するが、識別モデルがロード中から進まない
![ロード中.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/3298286c-7da1-9bb6-9e16-1daa73912d88.png)

- [x] 外カメラが機能するが、識別の過程でエラーが発生する
![識別中.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/44ab1839-ed16-467d-b2e4-fbbdd1719622.png)

30分以上も格闘することとなりましたが、`ChatGPT`に原因を聞きつつ、JSコードを見比べて原因を特定することができました（５つ以上考えられる原因を提示してくれるので、素人のtsumeが特定するのは大変）。
推測ですが、`Setup the webcam`のカメラを起動する順序と、外カメラを指定する際の表現によって、モデルがうまく働くかが変わってくるようです。

</details>

画像では分かりにくいですが外カメラが機能し、画像識別モデルも機能しています（ほうじ茶ラテを会議イスと識別しているのはご愛嬌👶）。

![外カメラ成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812402/cc682bd7-892e-0f70-21d2-1d120738e4f9.png)

### ７.実際に使ってみた
スマホから`CodePen`を使用し、実際に備品を識別できるか使ってみました。今回は実際にカメラで識別している様子と結果を、職場の仲間に端から観察してもらいました。

:::note info
ポジティブな感想
+ 同じような備品がいくつかあるので、これならうろ覚えでも間違えて遠くまで重いものを持って行くこともない
+ データや紙のように「情報を探す」手間がないのはよい
+ アイデア次第でもっと実用的にできそう
:::

:::note warn
改善要望
+ 普通のカメラ機能だけで使えないのか？ちょっと面倒

`CodePen`を使用したのは撮影する手間を省くこともありましたが、手慣れたツールで使いたいというニーズも得られました。`LINE Bot`を使用して、撮影した写真を基に結果を返してもらえば、誰でも使えて、スプレッドシートからもより詳細で正確な情報を得ることができます。
:::

個人的にはもう一段階レベルアップさせて、識別結果をさらに別のシステムへ連携する機能を持たせたいです。
 <dt> 現在 </dt>
  <dd>カメラで映すと識別結果・保管場所・個数がわかる</dd>
 
 <dt> レベルアップ </dt>
  <dd> 
  ・ カメラで映した情報が正しければ、ボタンアクションなどで別のシステムへ写真と日付などの情報が登録される（固定資産の棚卸など）</dd>
  <dd>
  ・ スプレッドシートに紐づけて、保管場所や数をリアルタイムで管理しやすく、見やすくする</dd>

# Teachable Machineを使ってみて
MLを使用した制作は初めてのトライでしたが、`Teachable Machine`はUIや機能がシンプルなこともあり、20分もかからずに簡単な画像識別モデルを作成することができました。

有形資産や人流の多い商業施設では、画像やポーズなどのデータに基づいたMLはよりたくさんの使い道がありそうだなと感じます。
また、今回は実際に形のある備品にフォーカスしましたが、他のユーザ作品を拝見すると、音声認識モデルを使用した複数外国言語の識別や、ポーズ認識モデルを使った顔・姿勢識別などを実装している例もありました。

MLと生成AIにほとんどの作業をしてもらった感覚ですが、この「AIならではのスマートさを使いこなすスマートさ」が大切だなーとしみじみするトライでした。