使用TensorFlow Lite Micro流程记录(带源码)

0 关于tflite micro

请添加图片描述

关于tflite micro在这里接不做过多介绍了,可以查看相关论文:TensorFlow Lite Micro: Embedded Machine Learning on TinyML Systems

我非常喜欢tflite micro,占用资源很少,是一个用来学习推理框架的好工程。

1 克隆仓库

在tensorflow的git里面,看到git已经迁移至一个单独的仓库

As of June 25, 2021, the TFLM codebase has moved to a stand-alone github repository.

于是执行命令:
git clone https://github.com/tensorflow/tflite-micro.git

2 编译静态库

求助了ChatGPT 4.0:

「在这个 https://github.com/tensorflow/tflite-micro , 怎么编译静态库?」

在TensorFlow Lite Micro的GitHub仓库中,你可以使用以下步骤来编译静态库:

首先,你需要克隆仓库:
git clone https://github.com/tensorflow/tflite-micro.git

进入克隆下来的仓库目录:
cd tflite-micro

使用make命令编译静态库:
make -f tensorflow/lite/micro/tools/make/Makefile TARGET=<TARGET> TARGET_ARCH=<ARCH> microlite

在上述命令中,<TARGET>应替换为你的目标平台(如linux),<ARCH>应替换为你的目标架构(如x86_64)。这将在tensorflow/lite/micro/tools/make/gen/<TARGET>_<ARCH>/lib/目录下生成一个名为libtensorflow-microlite.a的静态库。

请注意,你可能需要根据你的具体需求和环境来修改这些步骤。例如,你可能需要安装额外的依赖库,或者修改makefile来包含你需要的特性。

真是太棒了,于是我执行指令:

make -f tensorflow/lite/micro/tools/make/Makefile TARGET=linux TARGET_ARCH=x86_64 microlite

在 make/download/ 目录下,分别下载了flatbuffers、gemmlowp、kissfft、pigweed、ruy(如果你“网络不佳”,这里可能要花些精力)。

编译完成后,得到了静态库文件——
ar: creating gen/linux_x86_64_default/lib/libtensorflow-microlite.a

3 模型转换

以lenet5模型为例:

  1. 先把tflite模型转换为cpp文件:
    xxd -i lenet5.tflite > lenet5.cpp
  2. 包一下模型接口
    在lenet5.cpp的文件最后加入了这几行代码
    unsigned char * get_model_pointer()
    {
        return lenet5_tflite;
    }
    
    unsigned int get_model_size()
    {
        return lenet5_tflite_len;
    }
    
  3. 增加函数头文件
    #ifndef __MODEL_INTERFACE_H__
    #define __MODEL_INTERFACE_H__
    
    unsigned char * get_model_pointer();
    unsigned int get_model_size();
    
    #endif
    
    这样代码相对比较规范一些,当然也可以直接xxd成头文件直接引用。

4 编写工程

整个工程比较简单,为了方便引用头文件,我在tflite-micro下新建了一个demo文件夹:

.
├── demo
│   └── x86
│       ├── libtensorflow-microlite.a
│       ├── Makefile
│       ├── models
│       │   ├── lenet5.cpp
│       │   ├── lenet5.tflite
│       │   └── model_interface.h
│       ├── model_test.cpp
│       └── test

相关工程已经开源至github,欢迎star,欢迎pr~

5 编写demo

5.1 进行算子注册

首先可以看一下模型有哪些算子,以便于确认算子注册类型。(在netron查看tflite模型)
在这里插入图片描述

namespace {
  using OpResolver = tflite::MicroMutableOpResolver<8>;
  TfLiteStatus RegisterOps(OpResolver& op_resolver) {
    TF_LITE_ENSURE_STATUS(op_resolver.AddAdd());
    TF_LITE_ENSURE_STATUS(op_resolver.AddConv2D());
    TF_LITE_ENSURE_STATUS(op_resolver.AddFullyConnected());
    TF_LITE_ENSURE_STATUS(op_resolver.AddMaxPool2D());
    TF_LITE_ENSURE_STATUS(op_resolver.AddMul());
    TF_LITE_ENSURE_STATUS(op_resolver.AddReshape());
    TF_LITE_ENSURE_STATUS(op_resolver.AddSoftmax());
    TF_LITE_ENSURE_STATUS(op_resolver.AddTanh());
    return kTfLiteOk;
  }
}  // namespace

这个过程就是把要用到的算子进行注册。实际上我是缺什么算子加什么就好了。详细过程可以见算子注册debug过程

5.2 推理过程

TfLiteStatus LoadFloatModelAndPerformInference() {
  // get_model_pointer() 送入的就是lenet5的模型指针了
  const tflite::Model* model =
      ::tflite::GetModel(get_model_pointer());
  // 检查模型的版本是否匹配当前的 TFLite 版本。
  TFLITE_CHECK_EQ(model->version(), TFLITE_SCHEMA_VERSION);
  // printf("model->version() = %d\n", model->version()); // 好奇的话可以看看版本
  // 创建一个操作符解析器。
  OpResolver op_resolver; 
  // 注册模型中使用的操作符。
  TF_LITE_ENSURE_STATUS(RegisterOps(op_resolver)); 

  // Arena size just a round number. The exact arena usage can be determined
  // using the RecordingMicroInterpreter.
  // 定义一个 2MB 的张量内存区域(tensor_arena),用于解释器分配张量。先往大了写,之后再往小了调
  constexpr int kTensorArenaSize = 1024 * 2000; 
  uint8_t tensor_arena[kTensorArenaSize];
  
  // 创建解释器实例。
  tflite::MicroInterpreter interpreter(model, op_resolver, tensor_arena,
                                       kTensorArenaSize);
  // 调用 AllocateTensors 方法在 tensor_arena 中分配模型所需的张量内存。
  TF_LITE_ENSURE_STATUS(interpreter.AllocateTensors());

  float input_data[32*32];
  float output_data[10];

  for(int i = 0; i < 32*32; i++) {
    input_data[i] = 1.f;
  }
  // 获取输入和输出张量的指针,并检查它们是否为空。
  TfLiteTensor* input = interpreter.input(0);
  TFLITE_CHECK_NE(input, nullptr);
  TfLiteTensor* output = interpreter.output(0);
  TFLITE_CHECK_NE(output, nullptr);
  // 将输入数据复制到输入张量中。
  float* inTensorData = tflite::GetTensorData<float>(input);
  memcpy(inTensorData, input_data, input->bytes);
  // 调用 interpreter.Invoke() 执行推理。
  TF_LITE_ENSURE_STATUS(interpreter.Invoke());
  // 将输出张量的数据复制到 output_data 中,并打印第一个输出值。
  // 当然也可以直接打印 tflite::GetTensorData<float>(output)
  memcpy(&output_data[0], tflite::GetTensorData<float>(output), output->bytes);
  printf("output = %f\n", output_data[0]);
  // 打印使用的内存大小,现在可以根据这个数值去调整 kTensorArenaSize 了。
  printf("arena_used_bytes = %ld\n", interpreter.arena_used_bytes());
  return kTfLiteOk;
}

6 debug记录

6.1 缺少算子

make后运行./test, 报错:

Didn't find op for builtin opcode 'TANH'
Failed to get registration from op code TANH
 
Segmentation fault (core dumped)

问题很明确,没有进行tanh的算子注册。
具体怎么写呢?在tflite-micro/tensorflow/lite/micro/micro_mutable_op_resolver.h这里很容易找到。

6.2 注册表太小

正在一个一个加算子的过程中,遇到这么一个问题:

Couldn't register builtin op #22, resolver size 
is too small (5).

这是因为我定义的数量是5个。
using OpResolver = tflite::MicroMutableOpResolver<5>;
把这个增大到算子类型的数量一样就可以了。
这种小细节不注意的话确实容易把人劝退。

6.3 段错误

一旦执行到interpreter.input(0)->data.f[0] = 1.f;就段错误。
解决方式:
在makefile里面的CFLAGS -DTF_LITE_STATIC_MEMORY

6.4 进一步减小库体积

为了压缩体积,BUILD_TYPE使用了release进行编译,这期间会遇到MicroPrintf不支持的问题(release_with_logs是可以的),进行一些注释就可以。

以及进行-Os编译,可以减少很多体积占用。

7 实际部署

x86端调试完毕,接下来可以交叉编译tflite micro的库,然后代码移植到另一个工程就好了。

这个过程需要注意一下头文件不要少了。

这个过程可能会遇到诸多问题,欢迎评论交流。


相关源码已经开源至github,欢迎star,欢迎pr~

  • 31
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在STM32上部署TensorFlow Lite Micro需要以下步骤: 1. 准备开发环境:从TensorFlow官方GitHub库中获取TensorFlow Lite Micro的代码,并安装必要的软件工具链和开发环境,如GNU Arm Embedded Toolchain和STM32CubeMX。 2. 配置STM32CubeMX:使用STM32CubeMX配置你的STM32微控制器,包括选择正确的型号、引脚配置和时钟设置等。 3. 构建TensorFlow Lite Micro库:在你的开发环境中,使用Makefile或CMake来构建TensorFlow Lite Micro库。这将生成一个静态库文件(.a文件)。 4. 创建应用程序:根据你的具体应用需求,编写一个C/C++应用程序,包括载入模型、输入数据、运行推理以及处理输出结果等。你可以使用TensorFlow提供的示例代码作为起点。 5. 链接库文件:将TensorFlow Lite Micro库文件与你的应用程序进行链接,以便在编译时正确引用和调用库中的函数和结构。 6. 编译和烧录:使用GNU Arm Embedded Toolchain编译你的应用程序,并将生成的可执行文件烧录到STM32微控制器中。这可以通过ST-Link调试器或其他烧录工具来完成。 7. 测试和调试:在STM32上运行你的应用程序,并通过串口或其他调试接口来观察和验证推理结果。根据需要,进行调试和优化。 请注意,在部署TensorFlow Lite Micro到STM32上时,你需要确保你的STM32微控制器具备足够的计算和存储资源来运行模型。较大的模型可能需要更高级别的STM32系列,而较小的模型则可能适用于低端系列。还需要根据具体情况进行硬件和软件的优化,以确保性能和功耗的平衡。 此外,具体的步骤和细节可能因为使用的STM32型号、开发环境和TensorFlow Lite Micro版本而有所差异。在实际操作中,参考相关的文档、教程和示例代码,并参与相关的开发者社区来获取更详细和具体的指导。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值