(AIfES for Arduino)–高效微控制器人工智能开源框架
原文链接:链接: AIfES for Arduino由Jean-Luc Aufranc撰写。

4-1 IoT简介(物联网简介)

4-2 点亮未来之路: AI
让电脑有能力自我学习,这就是机器学习。
4-3 传感器新浪潮:AI + IoT
①云端计算

②边缘计算

4-4 Arduino软件开发ESP32应用
(一) 准备一块ESP32开发板
ESP32是一个可以用于控制的AI硬件开发板,可借两侧的输出入(I/O)管脚控制外部电子元件。还具有WIFI连网接口传送数据的功能。

(二)安装Arduino开发环境
下载Arduino IDE开发环境(链接: 下载Arduino IDE)
下载安装驱动程序链接:( 下载安装驱动程序链接)
新增ESP32开发板到Arduino IDE
在Arduino IDE中执行‘文件’->‘首选项’

打开 Arduino 软件,点击 “文件”→“首选项”,在 “附加开发板管理器网址” 中输入 https://dl.espressif.com/dl/package_esp32_index.json(这是 ESP32 开发板的管理网址,其实不填也行,不影响下面的步骤)
在Arduino IDE中执行‘工具’->‘开发板管理器’

搜索输入框esp32,按此安装

因为要在国外的网站下载,所以会失败。可以转为手动下载方式。
手动下载方式:
进入镜像仓库网址链接: 下载 ESP32 的支撑包 https://codechina.youkuaiyun.com/mirrors/espressif/arduino-esp32 下载 ESP32 的支撑包。该仓库的下载速度相对较快,能有效解决从国外网站下载速度慢或无法访问的问题。这个过程会很花很长时间,加上安装时间,约1个多小时。


连接ESP32,选择所使用的开发板和串口号

4-5 什么是AI人工智能
图像辨识、语音识别、数据处理的问题,转成程序语言,形成解决问题的规则。 让电脑自己学习规则,这就是机器学习( Machine Learning , ML)
4-5-1 机器学习
监督式学习 与 非监督式学习
监督式学习所使用的训练数据集合会事先给予标记 ,即准备一些问题和对应的答案给电脑后,通过合适的推理让它\ 自行找出其中的规则,并有能力针对类似的问题给出正确的回答,
常见的回归分析(Regression Analysis)与 统计分类(Classification)
4-5-2 神经网络
在机器学习中最主流的方法是类神经网络(Artificial Neural Network ,ANN,简称神经网络)

人工神经元

输入-就是问题
输出-就是答案
权重 和 偏值 就是要自我学习的参数 可以表示成:
输出
=
输入
1
×
权重
1
+
输入
2
×
权重
2
+
输入
3
×
权重
3
+
偏值
输出 = 输入1×权重1+输入2×权重2+输入3×权重3+偏值
输出=输入1×权重1+输入2×权重2+输入3×权重3+偏值
如果只有一个输入的神经元:

输出
=
输入
×
权重
+
偏值
输出=输入×权重+偏值
输出=输入×权重+偏值
回归问题
指的是找到两组数据之间的对应关系
资料如下:


有1条线能大致连接: y = 0.8337 x − 81.331 y=0.8337x-81.331 y=0.8337x−81.331
其实就是一个函数: 体重 = 身高 × 0.8337 − 81.331 体重=身高×0.8337-81.331 体重=身高×0.8337−81.331

用直线表示关系,不是很贴合。`(>﹏<)′
用分段的折线来解决非线性问题。( ̄︶ ̄)↗
采用 激活函数(activation function) 便能 在神经元输出之前进行非线性计算,再将值输出:

最常用的激活函数是 ReLU函数,小于转折点的输出数值都等于0

如果更贴合数据,就要导入更多非线性度,做法
将多个神经元连接在一起:
上下并排的神经元合称 神经层,

由于每个神经元共用一个激活函数,多个
有 激活函数 的神经元,等同提供更多非线性度,(ReLU 就是一次转折),所以生成函数更贴近数据:
神经网络
为了预测更加准确,可以加入更多输入数据,这些数据又称为-特征(Feature)

完整的神经网络又可以称为 - 模型 (model)

神经元的学习过程
神经元怎么学习?
一开始神经元什么都不会,因此 权重 和 偏值
都是乱猜的,
所以输出的答案也是不对的,不过它会比对你给
的数据来调整,直到它的输出与你给的资料一致:

损失函数 -计算预测值和标签误差的函数, 计算出来的值称为-损失值(loss) ,越大代表误差越多,
神经元有这个数值后就知道怎么调整它的参数,
不同问题会搭配不同损失函数,例如,回归问题就会使用
- 均方误差(Mean Squared Error,MSE)
每笔标签减预测值(即误差),取平方,再取平均值。
标签值: y 1 、 y 2 、 y 3 、 y 4 、 y 5 、 . . . 、 y n 、 标签值:y_1、y_2、y_3、y_4、y_5、...、y_n、 标签值:y1、y2、y3、y4、y5、...、yn、
预测值: y 1 ^ 、 y 2 ^ 、 y 3 ^ 、 y 4 ^ 、 y 5 ^ 、 . . . 、 y n ^ 、 预测值:\hat{y_1}、\hat{y_2}、\hat{y_3}、\hat{y_4}、\hat{y_5}、...、\hat{y_n}、 预测值:y1^、y2^、y3^、y4^、y5^、...、yn^、
均方差( M S E ) = 1 n ∑ i = 1 n ( y i − y i ^ ) 2 均方差(MSE)=\frac{1}{n} \sum_{i=1}^{n}(y_i-\hat{y_i})^2 均方差(MSE)=n1i=1∑n(yi−yi^)2
优化器(optimizer) 利用损失值来更新 权重 和 偏值,
调整神经元,让损失值降低,这个学习过程称为 - 训练 ,
由于更新的方向由后面层向前面层,又被称为 - 反向传播(BackPropagation,BP)
使用 梯度下降(Gradient descent) 法
朝向更小损失值的方向,修正参数,就能靠近最小损失值。

自适应调整学习率-η,加快训练速度。
加上动量因素冲出区域最低,而到达全域最低。 因此,优化器也各有不同。
4-6 机器学习函数库
安装AIfES for Arduino
AIfES(Artificial Inteligence for Embedded System)是
一个用C语言编写的 机器学习函数库 ,能在嵌入式设备中进行神经网络的训练,训练后的参数可以建立神经网络模型,能够直接载入训练好的权重参数进行预测。
搜索框中输入-AIfES

安装后…

4-7 学习更多的AIfES for Arduino的项目
链接: AIfES项目学习网址
链接1: wokwi上面的仿真项目链接1-(https://wokwi.com/projects/339063088500179539)
链接2: wokwi上面的仿真项目链接2-(https://wokwi.com/projects/326198897167827538)
实验耗材:Arduino 或 Arduino 兼容板
(一)实验目的
Wokwi 硬件模拟用ESP32开发板:
该示例展示了如何在 AIfES-Express 中使用训练数据从头开始训练神经网络。
使用神经网络学习一个异或门。
这里将异或门的四种不同状态作为训练数据输入。
网络结构是
输入层 2 - 中间层 3(Sigmoid 函数)- 输出层 1(Sigmoid 函数),并且使用 Sigmoid 函数作为激活函数。

计算使用 32 位浮点数进行。
异或的真值表 - 用于训练模型的数据集:
| 输入1 | 输入2 | 输出 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
在以下设备上进行了测试:
ESP32 开发套件(Wokwi 模拟)
(二)硬件连线

(三)程序代码
以下是带有注释的程序代码1:
/*
www.aifes.ai
https://github.com/Fraunhofer-IMS/AIfES_for_Arduino
Copyright (C) 2020-2022 Fraunhofer Institute for Microelectronic Circuits and Systems.
All rights reserved.
AIfES is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
AIfES-Express ESP32 dual core demo
ONLY FOR ESP32!!!!!!!
AIfES-Express is a simplified API for AIfES, which is directly integrated. So you can simply decide which variant you want to use.
The sketch shows an example of how a neural network is trained from scratch in AIfES-Express using training data.
An XOR gate is mapped here using a neural network.
The 4 different states of an XOR gate are fed in as training data here.
The network structure is 2-3(Sigmoid)-1(Sigmoid) and Sigmoid is used as activation function.
The calculation is done in float 32.
XOR truth table / training data
Input Output
0 0 0
0 1 1
1 0 1
1 1 0
You can find more AIfES tutorials here:
https://create.arduino.cc/projecthub/aifes_team
*/
// 定义训练数据集数量、输入数量和输出数量
#define DATASETS 4
#define INPUTS 2
#define OUTPUTS 1
// 定义用于多核任务处理的任务句柄
TaskHandle_t Core0TaskHnd;
// 定义内置 LED 的引脚编号
const int led = LED_BUILTIN;
// 标记神经网络是否已训练的布尔变量
bool NET_TRAINED = false;
// 定义输入数据的二维数组,存储 XOR 门的四种输入状态
float input_data[DATASETS][INPUTS] = {
{0.0f, 0.0f}, // Input data
{0.0f, 1.0f},
{1.0f, 0.0f},
{1.0f, 1.0f}
};
// 定义目标输出数据,对应 XOR 门的输出
float target_data[] = {0.0f, 1.0f, 1.0f, 0.0f}; // Target Data
// 定义输出数据数组,用于存储神经网络的计算结果
float output_data[DATASETS];
// 用于循环的变量
uint32_t i;
// 用于存储串口读取的字符串
String str;
void setup()
{
// 初始化串口通信,波特率为 115200
Serial.begin(115200);
// 设置内置 LED 引脚为输出模式
pinMode(led, OUTPUT);
// 打印程序信息
Serial.println ("AIfES - ESP32 dual core demo");
Serial.print ("Core ");
Serial.print (xPortGetCoreID());
Serial.println (": I am responsible for the AI and read the UART commands");
// 调用构建 AIfES 模型的函数(此处函数未给出具体实现)
build_AIfES_model();
// 创建一个任务并将其固定到核心 0,任务名为"CPU_0",任务栈大小为 1000,无参数传递,优先级为 1,任务句柄为 Core0TaskHnd,核心编号为 0
xTaskCreatePinnedToCore(CoreTask0,"CPU_0",1000,NULL,1,&Core0TaskHnd,0);
// IMPORTANT
// AIfES 要求训练时使用随机权重
// 这里通过模拟引脚 A5 的噪声生成随机种子
srand(analogRead(A5));
}
void loop()
{
// 读取串口数据并存储为字符串
str = Serial.readString();
// 如果字符串中包含"training"
if(str.indexOf("training") > -1)
{
// 打印训练信息
Serial.println("Training");
// 调用训练 AIfES 模型的函数,传入输入数据、目标数据和输出数据的指针
train_AIfES_model((float*)input_data,(float*)target_data,(float*)output_data);
// 设置已训练标志为真
NET_TRAINED = true;
Serial.println(F(""));
Serial.println(F("Results:"));
Serial.println(F("input 1:\tinput 2:\treal output:\tcalculated output:"));
// 遍历数据集,打印输入数据、目标输出和计算得到的输出
for (i = 0; i < DATASETS; i++)
{
Serial.print (input_data[i][0]);
Serial.print (F("\t\t"));
Serial.print (input_data[i][1]);
Serial.print (F("\t\t"));
Serial.print (target_data[i]);
Serial.print (F("\t\t"));
Serial.println(output_data[i], 5);
}
Serial.println(F("A learning success is not guaranteed"));
Serial.println(F("The weights were initialized randomly"));
Serial.println(F("You can repeat the training with >training<\n"));
Serial.println(F("Type >inference< to perform the inference"));
}
// 如果字符串中包含"inference"
if(str.indexOf("inference") > -1)
{
// 如果网络已训练
if(NET_TRAINED == true)
{
// 打印推理信息
Serial.println("inference");
// 初始化输出数据数组为 0
output_data[0] = 0.0f;
output_data[1] = 0.0f;
output_data[2] = 0.0f;
output_data[3] = 0.0f;
// 调用推理函数,传入输入数据和输出数据的指针
inference((float*)input_data,(float*)output_data);
Serial.println(F(""));
Serial.println(F("Inference results:"));
Serial.println(F("input 1:\tinput 2:\tcalculated output:"));
// 遍历数据集,打印输入数据和推理得到的输出
for (i = 0; i < DATASETS; i++)
{
Serial.print (input_data[i][0]);
Serial.print (F("\t\t"));
Serial.print (input_data[i][1]);
Serial.print (F("\t\t"));
Serial.println(output_data[i], 5);
}
}
else
{
// 如果网络未训练,打印提示信息
Serial.println("Net not trained");
}
}
}
// 核心 0 的任务函数
void CoreTask0( void * parameter )
{
Serial.print ("Core ");
Serial.print (xPortGetCoreID());
Serial.println(" (Task0): I switch the internal LED on and off");
Serial.println("");
Serial.println("Type >training< to start training");
Serial.println("Type >inference< to peform the inference");
for (;;)
{
// 点亮内置 LED
digitalWrite(led, HIGH);
delay (1000);
// 熄灭内置 LED
digitalWrite(led, LOW);
delay (1000);
// 让出处理器时间
yield();
}
}
以下是程序代码2:
/*
www.aifes.ai
https://github.com/Fraunhofer-IMS/AIfES_for_Arduino
Copyright (C) 2020-2022 Fraunhofer Institute for Microelectronic Circuits and Systems.
All rights reserved.
AIfES is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Short tutorial for Wokwi:
- Press the green "play" button to start the simulation
- After a short waiting time the program will show the following text:
AIfES-Express XOR training demo
Type >training< to start
- Type the word "training" in the window below the output and confirm with Enter
- The UART simulation and processing of the input takes some time
- Then the online training with AIfES starts
- A training success is of course not guaranteed, because the weights are randomly chosen
- If it takes too long (max. 1000 epochs) you can also stop and restart the simulation
- To train anew type "training" again
Of course, you can also create your own project.
To use AIfES in Wokwi you have to include the AIfES for Arduino library.
- Click on the "Library Manager" and then on the purple "plus" icon.
- Search for "aifes" and add the library.
--------------------
AIfES-Express XOR training demo
--------------------
Versions:
1.0.0 Initial version
AIfES-Express is a simplified API for AIfES, which is directly integrated. So you can simply decide which variant you want to use.
The sketch shows an example of how a neural network is trained from scratch in AIfES-Express using training data.
As in the example "0_AIfES-Express_XOR_Inference", an XOR gate is mapped here using a neural network.
The 4 different states of an XOR gate are fed in as training data here.
The network structure is 2-3(Sigmoid)-1(Sigmoid) and Sigmoid is used as activation function.
In the example, the weights are initialized randomly in a range of values from -2 to +2. The Gotrot initialization was inserted as an alternative and commented out.
For the training the ADAM Optimizer is used, the SGD Optimizer was commented out.
The optimizer runs a batch traininig over a maximum of 1000 epochs.
The early stopping is activated and stops the training when a desired target loss is reached.
The calculation is done in float 32.
XOR truth table / training data
Input Output
0 0 0
0 1 1
1 0 1
1 1 0
You can find more AIfES tutorials here:
https://create.arduino.cc/projecthub/aifes_team
*/
#include <aifes.h> // include the AIfES libary
#define DATASETS 4
#define FNN_3_LAYERS 3
#define PRINT_INTERVAL 10
// 定义全局变量,用于记录训练的 epoch 次数
uint32_t global_epoch_counter = 0;
// 自定义的打印损失函数
void printLoss(float loss)
{
// 增加 epoch 计数器
global_epoch_counter = global_epoch_counter + 1;
Serial.print(F("Epoch: "));
// 打印当前 epoch 次数乘以打印间隔
Serial.print(global_epoch_counter * PRINT_INTERVAL);
Serial.print(F(" / Loss: "));
// 打印损失值,保留 5 位小数
Serial.println(loss, 5);
}
void setup() {
// 初始化串口通信,波特率为 115200(如果需要,可以在串口监视器中更改)
Serial.begin(115200);
// 等待串口连接
while (!Serial);
// IMPORTANT
// AIfES 要求训练时使用随机权重
// 这里通过模拟引脚 A5 的噪声生成随机种子
srand(analogRead(A5));
// 打印程序名称
Serial.println(F("AIfES-Express XOR training demo"));
Serial.println(F("Type >training< to start"));
}
void loop() {
// 当串口有数据可读时
while(Serial.available() > 0 ){
// 读取串口数据并存储为字符串
String str = Serial.readString();
// 如果字符串中包含"training"
if(str.indexOf("training") > -1) //Keyword "training"
{
Serial.println(F("AIfES:"));
Serial.println(F(""));
Serial.println(F("rand test"));
// 打印随机数生成器生成的随机数
Serial.println(rand());
// 重置 epoch 计数器
global_epoch_counter = 0;
uint32_t i;
// -------------------------------- describe the feed forward neural network ----------------------------------
// neurons each layer
// FNN_structure[0] = input layer with 2 inputs
// FNN_structure[1] = hidden (dense) layer with 3 neurons
// FNN_structure[2] = output (dense) layer with 1 output
uint32_t FNN_structure[FNN_3_LAYERS] = {2,3,1};
// 设置密集层的激活函数
AIFES_E_activations FNN_activations[FNN_3_LAYERS - 1];
FNN_activations[0] = AIfES_E_sigmoid; // Sigmoid for hidden (dense) layer
FNN_activations[1] = AIfES_E_sigmoid; // Sigmoid for output (dense) layer
/* possible activation functions
AIfES_E_relu
AIfES_E_sigmoid
AIfES_E_softmax
AIfES_E_leaky_relu
AIfES_E_elu
AIfES_E_tanh
AIfES_E_softsign
AIfES_E_linear
*/
// AIfES Express 函数:计算所需的权重数量
uint32_t weight_number = AIFES_E_flat_weights_number_fnn_f32(FNN_structure,FNN_3_LAYERS);
Serial.print(F("Weights: "));
Serial.println(weight_number);
// FlatWeights 数组
//float FlatWeights[weight_number];
// 替代的权重数组
float *FlatWeights;
// 动态分配内存以存储权重数组
FlatWeights = (float *)malloc(sizeof(float)*weight_number);
// 填充 AIfES Express 结构体
AIFES_E_model_parameter_fnn_f32 FNN;
FNN.layer_count = FNN_3_LAYERS;
FNN.fnn_structure = FNN_structure;
FNN.fnn_activations = FNN_activations;
FNN.flat_weights = FlatWeights;
// -------------------------------- create the tensors ----------------------------------
// 定义输入数据,模拟 XOR 门的四种输入状态
float input_data[4][2] = {
{0.0f, 0.0f}, // Input data
{0.0f, 1.0f},
{1.0f, 0.0f},
{1.0f, 1.0f}
};
// 定义输入张量的形状
uint16_t input_shape[] = {DATASETS, (uint16_t)FNN_structure[0]}; // Definition of the input shape
// 创建输入张量,AITENSOR_2D_F32 是一个宏,用于简单地创建一个 float32 张量
aitensor_t input_tensor = AITENSOR_2D_F32(input_shape, input_data); // Macro for the simple creation of a float32 tensor. Also usable in the normal AIfES version
// 定义目标输出数据,对应 XOR 门的输出
float target_data[] = {0.0f, 1.0f, 1.0f, 0.0f}; // Target Data
// 定义目标张量的形状
uint16_t target_shape[] = {DATASETS, (uint16_t)FNN_structure[FNN_3_LAYERS - 1]}; // Definition of the target shape
// 创建目标张量
aitensor_t target_tensor = AITENSOR_2D_F32(target_shape, target_data); // Macro for the simple creation of a float32 tensor. Also usable in the normal AIfES version
// 定义输出数据数组,用于存储神经网络的计算结果
float output_data[DATASETS]; // Output data
// 定义输出张量的形状
uint16_t output_shape[] = {DATASETS, (uint16_t)FNN_structure[FNN_3_LAYERS - 1]}; // Definition of the output shape
// 创建输出张量
aitensor_t output_tensor = AITENSOR_2D_F32(output_shape, output_data); // Macro for the simple creation of a float32 tensor. Also usable in the normal AIfES version
// -------------------------------- init weights settings ----------------------------------
AIFES_E_init_weights_parameter_fnn_f32 FNN_INIT_WEIGHTS;
FNN_INIT_WEIGHTS.init_weights_method = AIfES_E_init_uniform;
/* init methods
AIfES_E_init_uniform
AIfES_E_init_glorot_uniform
AIfES_E_init_no_init //If starting weights are already available or if you want to continue training
*/
FNN_INIT_WEIGHTS.min_init_uniform = -2; // only for the AIfES_E_init_uniform
FNN_INIT_WEIGHTS.max_init_uniform = 2; // only for the AIfES_E_init_uniform
// -------------------------------- set training parameter ----------------------------------
AIFES_E_training_parameter_fnn_f32 FNN_TRAIN;
FNN_TRAIN.optimizer = AIfES_E_adam;
/* optimizers
AIfES_E_adam
AIfES_E_sgd
*/
FNN_TRAIN.loss = AIfES_E_mse;
/* loss
AIfES_E_mse,
AIfES_E_crossentropy
*/
FNN_TRAIN.learn_rate = 0.05f; // Learning rate is for all optimizers
FNN_TRAIN.sgd_momentum = 0.0; // Only interesting for SGD
FNN_TRAIN.batch_size = DATASETS; // Here a full batch
FNN_TRAIN.epochs = 1000; // Number of epochs
FNN_TRAIN.epochs_loss_print_interval = PRINT_INTERVAL; // Print the loss every x times
// 自定义的打印损失函数
// it must look like this: void YourFunctionName(float x)
FNN_TRAIN.loss_print_function = printLoss;
// 启用早停机制,当达到目标损失时自动停止学习
FNN_TRAIN.early_stopping = AIfES_E_early_stopping_on;
/* early_stopping
AIfES_E_early_stopping_off,
AIfES_E_early_stopping_on
*/
// 定义目标损失
FNN_TRAIN.early_stopping_target_loss = 0.004;
int8_t error = 0;
// -------------------------------- do the training ----------------------------------
// 在训练函数中,设置 FNN,初始化权重并执行训练
error = AIFES_E_training_fnn_f32(&input_tensor,&target_tensor,&FNN,&FNN_TRAIN,&FNN_INIT_WEIGHTS,&output_tensor);
// 处理训练中的错误
error_handling_training(error);
// -------------------------------- do the inference ----------------------------------
// AIfES Express 函数:执行推理
error = AIFES_E_inference_fnn_f32(&input_tensor,&FNN,&output_tensor);
// 处理推理中的错误
error_handling_inference(error);
// -------------------------------- print the results ----------------------------------
Serial.println(F(""));
Serial.println(F("Results:"));
Serial.println(F("input 1:\tinput 2:\treal output:\tcalculated output:"));
// 遍历数据集,打印输入数据、目标输出和计算得到的输出
for (i = 0; i < 4; i++) {
Serial.print (input_data[i][0]);
//Serial.print(((float* ) input_tensor.data)[i]); //Alternative print for the tensor
Serial.print (F("\t\t"));
Serial.print (input_data[i][1]);
Serial.print (F("\t\t"));
Serial.print (target_data[i]);
Serial.print (F("\t\t"));
Serial.println(output_data[i], 5);
//Serial.println(((float* ) output_tensor.data)[i], 5); //Alternative print for the tensor
}
Serial.println(F(""));
Serial.println(F("A learning success is not guaranteed"));
Serial.println(F("The weights were initialized randomly"));
Serial.println(F("You can repeat the training with >training<"));
}
else{
// 如果输入不是"training",打印"unknown"
Serial.println(F("unknown"));
}
}
}
// 处理训练中的错误函数
void error_handling_training(int8_t error_nr){
switch(error_nr){
case 0:
//Serial.println(F("No Error :)"));
break;
case -1:
Serial.println(F("ERROR! Tensor dtype"));
break;
case -2:
Serial.println(F("ERROR! Tensor shape: Data Number"));
break;
case -3:
Serial.println(F("ERROR! Input tensor shape does not correspond to ANN inputs"));
break;
case -4:
Serial.println(F("ERROR! Output tensor shape does not correspond to ANN outputs"));
break;
case -5:
Serial.println(F("ERROR! Use the crossentropy as loss for softmax"));
break;
case -6:
Serial.println(F("ERROR! learn_rate or sgd_momentum negative"));
break;
case -7:
Serial.println(F("ERROR! Init uniform weights min - max wrong"));
break;
case -8:
Serial.println(F("ERROR! batch_size: min = 1 / max = Number of training data"));
break;
case -9:
Serial.println(F("ERROR! Unknown activation function"));
break;
case -10:
Serial.println(F("ERROR! Unknown loss function"));
break;
case -11:
Serial.println(F("ERROR! Unknown init weights method"));
break;
case -12:
Serial.println(F("ERROR! Unknown optimizer"));
break;
case -13:
Serial.println(F("ERROR! Not enough memory"));
break;
default :
Serial.println(F("Unknown error"));
}
}
// 处理推理中的错误函数
void error_handling_inference(int8_t error_nr){
switch(error_nr){
case 0:
//Serial.println(F("No Error :)"));
break;
case -1:
Serial.println(F("ERROR! Tensor dtype"));
break;
case -2:
Serial.println(F("ERROR! Tensor shape: Data Number"));
break;
case -3:
Serial.println(F("ERROR! Input tensor shape does not correspond to ANN inputs"));
break;
case -4:
Serial.println(F("ERROR! Output tensor shape does not correspond to ANN outputs"));
break;
case -5:
Serial.println(F("ERROR! Unknown activation function"));
break;
case -6:
Serial.println(F("ERROR! Not enough memory"));
break;
default :
Serial.println(F("Unknown error"));
}
}
(四)程序运行结果
程序代码2运行的结果:
Epoch(训练周期):320次
Loss(损失函数值):0.00385,接近于零👌

@所有人
【全新视频教程】正点原子手把手教你学Arduino ESP32入门课程来啦!课程内容系统、全面且实用,覆盖了从基础到进阶,再到综合应用的完整学习路径!对于入门物联网和嵌入式开发的学习者来说是一个非常好的选择!【点击观看】
【正点原子】手把手教你快速入门Arduino ESP32
(目前上传60讲,后续课程将持续更新!)【资料下载】视频置顶评论区可下载视频配套资料
897

被折叠的 条评论
为什么被折叠?



