はじめに
XIAO ESP32S3でTensorflowを使ってみたかったのでEloquentTinyMLをインストールして、まずは、簡単な正弦関数を予測するサンプルプログラムを動かしてみた。
環境
XIAO ESP32S3
EloquentTinyML 2.4.4
Arduino IDE 1.8.9
Python 3.11
Windows 11 Pro
参考にした記事
やったこと
まずは、seeed studioのWikiページに行ってXIAO -> XIAO ESP32S3 (Sense) -> Getting Startedを開いて、Getting StartedのSoftware PreparationをStep 1からStep 4まで実行したあと、Blink(File->Examples->01.Basics->Blink)を動かして開発環境を確認しました。
次に、参考にした記事に従ってPythonでモデルを作って、BlinkのプログラムにTensorflowの初期設定のコードとSineの予測の部分をコピーして動かそうとしたところ、以下のコンパイルエラーが出てきました。調べたところ、Arduino IDE 2.1.1では動かないようで、1.8.9にすると動いたということが書いてあったので、同じように1.8.9にすると動きました。
コンパイルエラー
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のコード
#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/より)
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
以上