Tensorflowlite 部署到 arm开发板

本文详细介绍如何将TensorFlow Lite模型部署到ARM架构的开发板上,包括搭建环境、交叉编译、模型转换等关键步骤,并提供实际案例。

一 先在本机上操作

本机:Ubuntu18.04

1 下载TensorFlow

我选择的版本是:tensorflow-2.6.0
下载网址:

https://github.com/tensorflow/tensorflow
点master,选择tag,v2.6.0

(注:我是直接下载文件夹,进行解压。也可以 git clone,由于网速不行,clone不下来,就直接下载文件了,结果都一样)

下载依赖

#切换目录,切换到解压的tensorflow-2.6.0目录
cd  tensorflow-2.6.0
#执行download_dependencies.sh脚本,下载依赖,下载时,资源可能因网速下载失败,多试几次,增量下载。或者,哪一个下载不下来,会提示网址,手动下载,然后在sh脚本里将其下载代码注释掉即可。
./tensorflow/lite/tools/make/download_dependencies.sh

上述命令,会在make目录下生成downloads目录,目录下依赖目录如下:

在make目录下:ls

absl     eigen     fft2d        fp16      googletest  ruy
cpuinfo  farmhash  flatbuffers  gemmlowp  neon_2_sse

2 准备ARM的交叉编译环境

交叉编译选择的是:arm-linux-gnueabihf-gcc 7.5.0

2.1 下载安装包

位置:

https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/

gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

2.2 解压安装包

2.3 配置环境变量

这里本文配置用户私有环境变量

vim .bashrc
#末尾添加:
export PATH=$PATH:/解压位置/gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux/bin
#配置生效
source .bashrc 
(base) power@raspberrypi:~$ ./load_iden -v 1 -m ./model/load_iden_v2_quant.tflite 
-i ./light.bin -l ./multilabel.txt
INFO: Loaded model ./model/load_iden_v2_quant.tflite
INFO: tensors size:173 
INFO: inputs:1
INFO: wanted with,height,channels:20,28,1
INFO: average time:19.954ms 
INFO: predict result:
INFO: 【0,1,0,0,0】 白炽灯

2.4 查看编译器版本

直接在命令窗口输入命令:

arm-linux-gnueabihf-gcc --version

3 交叉编译生成静态库

#所在目录:tensorflow/lite/tools/make
#执行下面脚本
./build_rpi_lib.sh

主要目的:生成libtensorflow-lite.a静态库,交叉编译的时候用到
结果展示:

#所在目录:tensorflow/lite/tools/make
cd cd gen/rpi_armv7l
ls
bin  lib  obj
cd lib
benchmark-lib.a  libtensorflow-lite.a

4 官方Demo :label_image的编译

4.1 整理头文件

cd tensorflow-2.6.0/tensorflow/lite
find  -name "*.h" | tar -cf headers.tar -T -#这一步,是将lite头文件压缩打包

#找另外任意一个地方(离开tensorflow-2.6.0目录),新建一个目录,将我们需要进行编译相关的文件放在一起
mkdir test
cd test
mkdir -p include/tensorflow/lite#这一步
tar xvf headers.tar -C include/tensorflow/lite#将前面压缩打包的文件拷贝过来,解压

将absl flatbuffers gmock gtest tensorflow头文件也移动include目录下:
演示:flatbuffers,其他同理

#在test目录下操作
mkdir -p include/flatbuffers
cp tensorflow-2.6.0/tensorflow/lite/tools/make/downloads/flatbuffers/include/flatbuffers /*  ./include/flatbuffers/

将tensorflow-2.6.0/tensorflow/lite/examples目录下的label_image目录也拷贝到test目录下

将tensorflow-2.6.0/tensorflow/lite/tools/make/gen/rpi_armv7l目录下的lib目录也拷贝到test目录下

即:test目录下目录

include  label_image  lib

4.2 cmake ,make 进行编译

cd test/label_image

修改CMakeLists.txt;#alter 标识,是我修改的地方

#                                                                                                                                                                                                              
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
 
 
# Builds the minimal Tensorflow Lite example.
 
cmake_minimum_required(VERSION 2.9)
project(label_image)
set(CMAKE_VERBOSE_MAKEFILE on)

#alter
set(tools /opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf)
                                                                                                                                                                                                
#include_directories(../../tensorflow-2.6.3/tensorflow/lite)
include_directories(../include/flatbuffers)
include_directories(../include/tensorflow/lite)
include_directories(../include)
 
set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)
 
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "-O3 -static  -pthread")
 
 #alter
LINK_LIBRARIES("/mnt/toArm/test/lib/libtensorflow-lite.a")
 
add_executable(label_image
  label_image.cc bitmap_helpers.cc 
)
TARGET_LINK_LIBRARIES(label_image  dl)

修改label_image.cc:

/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/examples/label_image/label_image.h"

#include <fcntl.h>      // NOLINT(build/include_order)
#include <getopt.h>     // NOLINT(build/include_order)
#include <sys/time.h>   // NOLINT(build/include_order)
#include <sys/types.h>  // NOLINT(build/include_order)
#include <sys/uio.h>    // NOLINT(build/include_order)
#include <unistd.h>     // NOLINT(build/include_order)/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/examples/label_image/label_image.h"

#include <fcntl.h>      // NOLINT(build/include_order)
#include <getopt.h>     // NOLINT(build/include_order)
#include <sys/time.h>   // NOLINT(build/include_order)
#include <sys/types.h>  // NOLINT(build/include_order)
#include <sys/uio.h>    // NOLINT(build/include_order)
#include <unistd.h>     // NOLINT(build/include_order)

#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_set>
#include <vector>

#include "tensorflow/lite/tools/make/downloads/absl/absl/memory/memory.h"
#include "tensorflow/lite/examples/label_image/bitmap_helpers.h"
#include "tensorflow/lite/examples/label_image/get_top_n.h"
#include "tensorflow/lite/examples/label_image/log.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/optional_debug_tools.h"
#include "tensorflow/lite/profiling/profiler.h"
#include "tensorflow/lite/string_util.h"
#include "tensorflow/lite/tools/command_line_flags.h"
#include "tensorflow/lite/tools/delegates/delegate_provider.h"

namespace tflite {
   
   
namespace label_image {
   
   

double get_us(struct timeval t) {
   
    return (t.tv_sec * 1000000 + t.tv_usec); }

using TfLiteDelegatePtr = tflite::Interpreter::TfLiteDelegatePtr;
using ProvidedDelegateList = tflite::tools::ProvidedDelegateList;
#if 0
template <class T>
void resize(T* out, uint8_t* in, int image_height, int image_width,
            int image_channels, int wanted_height, int wanted_width,
            int wanted_channels, Settings* s) {
   
   
  cout<< "11111111111"<<endl
  int number_of_pixels = image_height * image_width * image_channels;
  std::unique_ptr<Interpreter> interpreter(new Interpreter);

  int base_index = 0;

  LOG(INFO)<< "11111111111"

  // two inputs: input and new_sizes
  interpreter->AddTensors(2, &base_index);
  // one output
  interpreter->AddTensors(1, &base_index);
  // set input and output tensors
  interpreter->SetInputs({
   
   0, 1});
  interpreter->SetOutputs({
   
   2});

  LOG(INFO)<< "11111111111"
  // set parameters of tensors
  TfLiteQuantizationParams quant;
  interpreter->SetTensorParametersReadWrite(
      0, kTfLiteFloat32, "input",
      {
   
   1, image_height, image_width, image_channels}, quant);
  interpreter->SetTensorParametersReadWrite(1, kTfLiteInt32, "new_size", {
   
   2},
                                            quant);
  LOG(INFO)<< "11111111111"
  interpreter->SetTensorParametersReadWrite(
      2, kTfLiteFloat32, "output",
      {
   
   1, wanted_height, wanted_width, wanted_channels}, quant);

  LOG(INFO)<< "11111111111"
  ops::builtin::BuiltinOpResolver resolver;
  const TfLiteRegistration* resize_op =
      resolver.FindOp(BuiltinOperator_RESIZE_BILINEAR, 1);
  auto* params = reinterpret_cast<TfLiteResizeBilinearParams*>(
      malloc(sizeof(TfLiteResizeBilinearParams)));
  params->align_corners = false;
  params->half_pixel_centers = false;
  interpreter->AddNodeWithParameters({
   
   0, 1}, {
   
   2}, nullptr, 0, params, resize_op,
                                     nullptr);
  LOG(INFO)<< "interpreter->AllocateTensors()"

  interpreter->AllocateTensors();

  // fill input image
  // in[] are integers, cannot do memcpy() directly
  auto input = interpreter->typed_tensor<float>(0);
  for (int i = 0; i < number_of_pixels; i++) {
   
   
    input[i] = in[i];
  }

  // fill new_sizes
  interpreter->typed_tensor<int>(1)[0] = wanted_height;
  interpreter->typed_tensor<int>(1)[1] = wanted_width;
  LOG(INFO)<< "interpreter->Invoke()"
  interpreter->Invoke();

  auto output = interpreter->typed_tensor<float>(2);
  auto output_number_of_pixels = wanted_height * wanted_width * wanted_channels;

  for (int i = 0; i < output_number_of_pixels; i++) {
   
   
    switch (s->input_type) {
   
   
      case kTfLiteFloat32:
        out[i] = (output[i] - s->input_mean) / s->input_std;
        break;
      case kTfLiteInt8:
        out[i] = static_cast<int8_t>(output[i] - 128);
        break;
      case kTfLiteUInt8:
        out[i] = static_cast<uint8_t>(output[i]);
        break;
      default:
        break;
    }
  }
}
#endif
// Takes a file name, and loads a list of labels from it, one per line, and
// returns a vector of the strings. It pads with empty strings so the length
// of the result is a multiple of 16, because our model expects that.
TfLiteStatus ReadLabelsFile(const string& file_name,
                            std::vector<string>* result,
                            size_t* found_label_count) {
   
   
  std::ifstream file(file_name);
  if (!file) {
   
   
    LOG(ERROR) << "Labels file " << file_name << " not found";
    return kTfLiteError;
  }
  result->clear();
  string line;
  while (std::getline(file, line)) {
   
   
    result->push_back(line);
  }
  *found_label_count = result->size();
  const int padding = 16;
  while (result->size() % padding) {
   
   
    result->emplace_back();
  }
  return kTfLiteOk;
}

void PrintProfilingInfo(const profiling::ProfileEvent* e,
                        uint32_t subgraph_index, uint32_t op_index,
                        TfLiteRegistration registration) {
   
   
  // output something like
  // time (ms) , Node xxx, OpCode xxx, symbolic name
  //      5.352, Node   5, OpCode   4, DEPTHWISE_CONV_2D

  LOG(INFO) << std::fixed << std::setw(10) << std::setprecision(3)
            << (e->end_timestamp_us - e->begin_timestamp_us) / 1000.0
            << ", Subgraph " << std::setw(3) << std::setprecision(3)
            << subgraph_index << ", Node " << std::setw(3)
            << std::setprecision(3) << op_index << ", OpCode " << std::setw(3)
            << std::setprecision(3) << registration.builtin_code << ", "
            << EnumNameBuiltinOperator(
                   static_cast<BuiltinOperator>(registration.builtin_code));
}

/// 使用的是mobilenet_v2_1.0_224_quant.tflite 量化后模型
void RunInference(Settings* settings)
{
   
   
  std::unique_ptr<tflite::FlatBufferModel> model;
  std::unique_ptr<tflite::Interpreter> interpreter;
  model = tflite::FlatBufferModel::BuildFromFile(settings->model_name.c_str());
  if (!model) {
   
   
    LOG(ERROR) << 
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值