这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【ESP-IDF系列】全流程打通,使用Tensorflow训练模型并且部署到ES

共2条 1/1 1 跳转至

【ESP-IDF系列】全流程打通,使用Tensorflow训练模型并且部署到ESP32S3进行推理

工程师
2025-08-26 20:11:20     打赏

简介

最近这一段时间在学习机器学习,也尝试将一个SkLearn的模型部署到了PocketBeagle 2 上(感谢论坛提供的试用机会), 发现效果是真的不错。所以我就在想有没有什么便捷的方式能够将一个简单的模型部署到单片机上来实现某种行为的边缘计算。于是经过我的搜索后找到了一个ESP32的基于Tensorflow lite的库。如下图所示。


image.png

上述的这个库是基于TF官方的TF-lite进行ESP32-S3的适配。所以对应TF官方的介绍如下图所示。


image.png

至此逻辑关系已经被整理清楚了, TFlite是针对资源受限的Machine Learing 库, 而乐鑫的 esp-tflite-micro 是TFlite 对ESP32设备的一个具体实现。


那么在本篇文章中将带着大家从零开始进行Demo的烧录(测试意图)、模型训练, 转换成C语言数组。然后到模型的部署,最终实现和模型一样的效果。阅读这篇文章你最好具备一些基础的Machine learning 和 Deep learning 知识。


Hello World Demo 烧录


1- 首先,你本地已经安装好了IDF的环境, 你只需要在任意一个IDF的项目目录下执行下述命令来添加esp-tflite-micro的依赖

idf.py add-dependency "esp-tflite-micro"

2- 基于现在的项目新建Helloworld的项目

idf.py create-project-from-example "esp-tflite-micro:hello_world"

之后便可以对当前的demo进行烧录了。当然重点不在这里。下述截图为实际Demo的实际运行效果。

image.png



训练模型

对于模型的训练,我这里环境依赖是被Anaconda进行管理的, 使用的是TF的完整版进行训练。Demo的HelloWorld训练代码来自于TFlite, 可以在HelloWorldDemo中的readme中找到对应的链接。我们对其进行少量的修改使其可以直接在Jupyter notebook中运行。即Python代码。移除外部参数传递。

下面是代码的核心步骤。

def get_data():
    """
    Generate a set of random `x` values and calculate their sine values.
    """
    x_values = np.random.uniform(low=0, high=2 * math.pi, size=1000).astype(np.float32)
    np.random.shuffle(x_values)
    y_values = np.sin(x_values).astype(np.float32)
    return (x_values, y_values)

首先生成随机的正选随机数,进行打乱,然后返回总体的X和Y向量。

def create_model() -> tf.keras.Model:
    model = tf.keras.Sequential([
        tf.keras.Input(shape=(1,)),       
        tf.keras.layers.Dense(16, activation="relu"),
        tf.keras.layers.Dense(16, activation="relu"),
        tf.keras.layers.Dense(1)
    ])
    model.compile(optimizer="adam", loss="mse", metrics=["mae"])
    return model

模型采用的是一个三层的神经网络,输入1, 输出1. 其中两层每层一共16个神经元用来学习特征。

def main():
    x_values, y_values = get_data()
    trained_model = train_model(EPOCHS, x_values, y_values)

    # Convert and save the model to .tflite
    tflite_model = convert_tflite_model(trained_model)
    save_tflite_model(tflite_model, SAVE_DIR, model_name="hello_world_float.tflite")

然后对模型进行训练,同时转换成tflite的格式。

image.png

之后使用xxd将这个tflite的模型抓换成C语言的数组。

xxd -i hello_world_int8.tflite > hello_world_model_data.cc


至此模型的训练和转换已经完成了。


部署模型

对于模型的部署,HelloWorld给了我们一个很好的示例。我们只需要把我们转换成CC文件中的c语言数组拷贝到Model.CC文件中即可。

image.png

注意,并不能全拷贝,只拷贝数组部分即可。和下方的数组长度。

image.png

注意数组的类型,不要全拷贝。 然后修改Model内extern 暴露的数组名称和模型数组名称一致。

image.png

然后修改SetUpfunction中的数组名称为模型的名称。

image.png


由于我们训练的模型没有进行量化,所以直接使用未经量化的float类型即可。将代码修改成下述代码。使用了Float类型进行输入和输出。

// The name of this function is important for Arduino compatibility.
void loop()
{
  // Calculate an x value to feed into the model. We compare the current
  // inference_count to the number of inferences per cycle to determine
  // our position within the range of possible x values the model was
  // trained on, and use this to calculate a value.
  float position = static_cast<float>(inference_count) /
                   static_cast<float>(kInferencesPerCycle);
  float x = position * kXrange;

  input->data.f[0] = x;

  // Run inference, and report any error
  TfLiteStatus invoke_status = interpreter->Invoke();
  if (invoke_status != kTfLiteOk)
  {
    MicroPrintf("Invoke failed on x: %f\n",
                static_cast<double>(x));
    return;
  }

  float y = output->data.f[0];

  // Output the results. A custom HandleOutput function can be implemented
  // for each supported hardware target.
  HandleOutput(x, y);

  // Increment the inference_counter, and reset it if we have reached
  // the total number per cycle
  inference_count += 1;
  if (inference_count >= kInferencesPerCycle)
    inference_count = 0;
}

需要注意的是,如果你的模型进行过量化,那就根据对应的量化参数进行传递。否则模型精度将会很低。


实验效果

image.png

模型的X输入和Y输出。满足预期。


hello_world.zip




关键词: ESP-IDF     机器学习     Tensorflow    

工程师
2025-08-27 21:18:17     打赏
2楼

666,训练过程都有了。下次搞个人脸识别试试板子的性能啊


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]