Teachable Machineを用いてクラッピーの拍手認識

# はじめに
[#クラッピーチャレンジ Advent Calendar 2020](https://adventar.org/calendars/5187) 3日目の記事です。
過去にも拍手認識をしてきたのですが、今回は[Teachable Machine](https://teachablemachine.withgoogle.com/train/audio)を使って拍手認識していきます。

- [Azure ML Studioを用いてクラッピーの拍手認識](https://qiita.com/SatoshiGachiFujimoto/items/c9a485612215037b2600)
- [クラッピーの拍手をカウントしてみた（物理）](https://qiita.com/SatoshiGachiFujimoto/items/ce2976dd0e444accd0f5)

# 開発環境
- Windows 10 PC
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">プライムデーで安かったので、予備PC<br>【基本スペック】<br>OS：Windows 10 Home 64bit、CPU：インテル Core i7-9750H、GPU：NVIDIA GeForce GTX 1650 Ti Max-Q デザイン 4GB GDDR5、メモリ：16GB（8GB ×2）、SSD：512GB、液晶パネル：15.6インチ、フルHD（1,920×1,080）、リフレッシュレート120Hz <a href="https://t.co/S8RIsayFPY">pic.twitter.com/S8RIsayFPY</a></p>&mdash; 藤本賢志(ガチ本)@XRKaigi (@sotongshi) <a href="https://twitter.com/sotongshi/status/1317758401946947591?ref_src=twsrc%5Etfw">October 18, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
- Chromeブラウザ

# 導入
1．[Teachable Machine](https://teachablemachine.withgoogle.com/)を開きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/d41a9af3-a644-9f37-6a01-b92be3ca004a.png)

2．「使ってみる」から、音声プロジェクトをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/f033044b-5554-255d-b492-ce348e6e1827.png)

3．バックグラウンドノイズをマイクから録音しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/2bef5036-60fe-e339-c6a4-40a21e0f8426.png)

4．生活音などを20秒間録音し、「サンプルを抽出」をクリックすると、学習用のデータが溜まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/c748a122-5919-ab1f-b2c8-8cd5239b7902.png)

5．次に実際に認識させたい拍手音を2秒間録音し、サンプルを抽出していきます。クラッピーが手元にある人はパチパチしてください。僕は手元になかったので、過去の動画から学習データを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/6bdc44cf-f61f-22af-80bc-2fc75f4802b9.png)

6．バックグラウンドノイズが20個以上、認識させたい音が8個以上、サンプルが集まったら、トレーニングします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/3777f460-1557-5b1f-d65b-f3a1ec47405f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/bb5ab3e8-dda9-07c4-d28e-33bc56f6aede.png)

7．トレーニングできたら、マイク入力がオンになっているので、拍手して認識できるか確認してみましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/222ec5bc-7d44-711c-b7b5-677bb953e884.png)

# 実行結果

実行結果の動画をご覧ください。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">TeachableMachineを用いて拍手認識 <a href="https://twitter.com/hashtag/%E3%82%AF%E3%83%A9%E3%83%83%E3%83%94%E3%83%BC%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#クラッピーチャレンジ</a> <a href="https://twitter.com/hashtag/TeachableMachine?src=hash&amp;ref_src=twsrc%5Etfw">#TeachableMachine</a> <a href="https://t.co/06DuzTlI3N">pic.twitter.com/06DuzTlI3N</a></p>&mdash; 藤本賢志(ガチ本)@XRKaigi (@sotongshi) <a href="https://twitter.com/sotongshi/status/1334339440441876482?ref_src=twsrc%5Etfw">December 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

モデルのエクスポートや共有もできます。今回のモデルは[こちら](https://teachablemachine.withgoogle.com/models/Ic-n9CMI8/)から利用できます。

JavaScriptのサンプルコード

~~~js
<div>Teachable Machine Audio Model</div>
<button type="button" onclick="init()">Start</button>
<div id="label-container"></div>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/speech-commands@0.4.0/dist/speech-commands.min.js"></script>

<script type="text/javascript">
    // more documentation available at
    // https://github.com/tensorflow/tfjs-models/tree/master/speech-commands

    // the link to your model provided by Teachable Machine export panel
    const URL = "https://teachablemachine.withgoogle.com/models/Ic-n9CMI8/";

    async function createModel() {
        const checkpointURL = URL + "model.json"; // model topology
        const metadataURL = URL + "metadata.json"; // model metadata

        const recognizer = speechCommands.create(
            "BROWSER_FFT", // fourier transform type, not useful to change
            undefined, // speech commands vocabulary feature, not useful for your models
            checkpointURL,
            metadataURL);

        // check that model and metadata are loaded via HTTPS requests.
        await recognizer.ensureModelLoaded();

        return recognizer;
    }

    async function init() {
        const recognizer = await createModel();
        const classLabels = recognizer.wordLabels(); // get class labels
        const labelContainer = document.getElementById("label-container");
        for (let i = 0; i < classLabels.length; i++) {
            labelContainer.appendChild(document.createElement("div"));
        }

        // listen() takes two arguments:
        // 1. A callback function that is invoked anytime a word is recognized.
        // 2. A configuration object with adjustable fields
        recognizer.listen(result => {
            const scores = result.scores; // probability of prediction for each class
            // render the probability scores per class
            for (let i = 0; i < classLabels.length; i++) {
                const classPrediction = classLabels[i] + ": " + result.scores[i].toFixed(2);
                labelContainer.childNodes[i].innerHTML = classPrediction;
            }
        }, {
            includeSpectrogram: true, // in case listen should return result.spectrogram
            probabilityThreshold: 0.75,
            invokeCallbackOnNoiseAndUnknown: true,
            overlapFactor: 0.50 // probably want between 0.5 and 0.75. More info in README
        });

        // Stop the recognition in 5 seconds.
        // setTimeout(() => recognizer.stopListening(), 5000);
    }
</script>
~~~

p5.jsのサンプルコード

~~~p5.js
<div>Teachable Machine Audio Model - p5.js and ml5.js</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
<script type="text/javascript">
  // Global variable to store the classifier
let classifier;

// Label
let label = 'listening...';

// Teachable Machine model URL:
let soundModel = 'https://teachablemachine.withgoogle.com/models/Ic-n9CMI8/';


function preload() {
  // Load the model
  classifier = ml5.soundClassifier(soundModel + 'model.json');
}

function setup() {
  createCanvas(320, 240);
  // Start classifying
  // The sound model will continuously listen to the microphone
  classifier.classify(gotResult);
}

function draw() {
  background(0);
  // Draw the label in the canvas
  fill(255);
  textSize(32);
  textAlign(CENTER, CENTER);
  text(label, width / 2, height / 2);
}


// The model recognizing a sound will trigger this event
function gotResult(error, results) {
  if (error) {
    console.error(error);
    return;
  }
  // The results are in an array ordered by confidence.
  // console.log(results[0]);
  label = results[0].label;
}
</script>
~~~

tflite浮動小数点モデルに変換し、ダウンロードも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/e817c1bc-ee6a-7da0-553e-1a6b4ec50fe7.png)

# まとめ
Teachable Machineを用いて簡単に拍手の認識を行うことができました！
割と打音ならなんでも検知しちゃう感じなので学習データをもっと工夫していく必要がありそうです。
あとは、PythonからリアルタイムでTensorflow Liteを使いたいですね。
お疲れ様でした。