XIAO ESP32S3にTinyMLをインストールしてみた。


### はじめに
XIAO ESP32S3でTensorflowを使ってみたかったのでEloquentTinyMLをインストールして、まずは、簡単な正弦関数を予測するサンプルプログラムを動かしてみた。

![xiao_esp32_s3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/27e41831-13d6-1964-e116-24a135df4cce.jpeg)

### 環境
XIAO ESP32S3
EloquentTinyML 2.4.4
Arduino IDE 1.8.9
Python 3.11
Windows 11 Pro


### 参考にした記事
https://eloquentarduino.com/tensorflow-lite-esp32/

### やったこと
まずは、[seeed studioのWikiページ](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/)に行って[XIAO -> XIAO ESP32S3 (Sense) -> Getting Started](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/)を開いて、[Getting Started](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/)のSoftware PreparationをStep 1からStep 4まで実行したあと、Blink（File->Examples->01.Basics->Blink）を動かして開発環境を確認しました。
次に、[参考にした記事](https://eloquentarduino.com/tensorflow-lite-esp32/)に従ってPythonでモデルを作って、BlinkのプログラムにTensorflowの初期設定のコードとSineの予測の部分をコピーして動かそうとしたところ、以下のコンパイルエラーが出てきました。調べたところ、Arduino IDE 2.1.1では動かないようで、1.8.9にすると動いたということが書いてあったので、同じように1.8.9にすると動きました。
##### ![sineNN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/40873263-e67e-a37e-4c56-3f9e468889b1.png)

##### コンパイルエラー
```
c:\Users\User1\Documents\Arduino\libraries\EloquentTinyML\src\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_HWC_q15_fast_nonsquare.c:1: fatal error: opening dependency file C:\Users\User1\AppData\Local\Temp\arduino\sketches\25A51BD3B31BC7D774EE9260A84C8A6B\libraries\EloquentTinyML\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_HWC_q15_fast_nonsquare.c.d: No such file or directory
 #if !defined(ESP32)
 
compilation terminated.
c:\Users\User1\Documents\Arduino\libraries\EloquentTinyML\src\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_1x1_HWC_q7_fast_nonsquare.c:1: fatal error: opening dependency file C:\Users\User1\AppData\Local\Temp\arduino\sketches\25A51BD3B31BC7D774EE9260A84C8A6B\libraries\EloquentTinyML\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_1x1_HWC_q7_fast_nonsquare.c.d: No such file or directory
 #if !defined(ESP32)
 
compilation terminated.
c:\Users\User1\Documents\Arduino\libraries\EloquentTinyML\src\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_HWC_q7_basic_nonsquare.c:1: fatal error: opening dependency file C:\Users\User1\AppData\Local\Temp\arduino\sketches\25A51BD3B31BC7D774EE9260A84C8A6B\libraries\EloquentTinyML\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_HWC_q7_basic_nonsquare.c.d: No such file or directory
 #if !defined(ESP32)
 
compilation terminated.
c:\Users\User1\Documents\Arduino\libraries\EloquentTinyML\src\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_HWC_q7_fast_nonsquare.c:1: fatal error: opening dependency file C:\Users\User1\AppData\Local\Temp\arduino\sketches\25A51BD3B31BC7D774EE9260A84C8A6B\libraries\EloquentTinyML\eloquent_tinyml\tensorflow\arm\tensorflow\lite\micro\tools\make\downloads\cmsis\CMSIS\NN\Source\ConvolutionFunctions\arm_convolve_HWC_q7_fast_nonsquare.c.d: No such file or directory
 #if !defined(ESP32)
 
compilation terminated.

exit status 1

Compilation error: exit status 1
```

##### ESP32のコード
```c
#include <EloquentTinyML.h>
 

/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/Blink
*/

#include "SineNN.h"

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);

  while (!sineNN.begin()) {
    Serial.print("Error in NN initialization: ");
    Serial.println(sineNN.getErrorMessage());
  }
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(1000);                      // wait for a second
  digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second

  for (int i = 0; i < 20; i++) {
        digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
        // pick x from 0 to PI
        float x = 3.14f * i / 20.0f;
        // even if the input vector is made of a single value
        // you ALWAYS need to create an array
        float input[1] = { x };

        float y_true = sin(x);
        // to run the network, call `predict()`
        float y_pred = sineNN.predict(input);

        Serial.print("sin(");
        Serial.print(x);
        Serial.print(") = ");
        Serial.print(y_true);
        Serial.print("\t predicted: ");
        Serial.println(y_pred);
        delay(1000);
       digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
    }
}
```

モデルを作るためのPytonコード（https://eloquentarduino.com/tensorflow-lite-esp32/より）
```python
import math
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers
from sklearn.model_selection import train_test_split
from everywhereml.code_generators.tensorflow import tf_porter

def get_model():
    x_values = np.random.uniform(low=0, high=2 * math.pi, size=1000)
    y_values = np.sin(x_values)
    x_train, x_test, y_train, y_test = train_test_split(x_values, y_values, test_size=0.3)
    x_train, x_validate, y_train, y_validate = train_test_split(x_train, y_train, test_size=0.3)

    # create a NN with 2 layers of 16 neurons
    model = tf.keras.Sequential()
    model.add(layers.Dense(16, activation='relu', input_shape=(1,)))
    model.add(layers.Dense(16, activation='relu'))
    model.add(layers.Dense(1))
    model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
    model.fit(x_train, y_train, epochs=100, batch_size=16, validation_data=(x_validate, y_validate))

    return model, x_train, y_train


tf_model, x_train, y_train = get_model()
# tf_porter() requires:
#   1. the neural network model
#   2. the input data (to detect the input dimensions)
#   3. the output labels (to detect the number of classes - if classification)
#
# Passing `instance_name` will create an instance of the model, so you don't have to
# `area_size` is to control how much memory to allocate for the network
# It is a trial-and-error process
porter = tf_porter(tf_model, x_train, y_train)
cpp_code = porter.to_cpp(instance_name='sineNN', arena_size=4096)

print(cpp_code)
```

### 参考文献
https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
https://eloquentarduino.com/tensorflow-lite-esp32/
https://github.com/eloquentarduino/EloquentTinyML
https://www.tensorflow.org/lite/examples/image_classification/overview
https://docs.arduino.cc/software/ide-v1/tutorials/installing-libraries

以上