爱笑的小姐姐 · 2021年10月26日

Tengine lite Windows Clion 配置

感谢虫叔[@圈圈虫]的邀请,准备出个Tengine-lite的学习笔记与测评。

刚看NCNN没多久,发了几篇学习笔记,碰巧被虫叔看到,想来也是非常幸运了。

昨天刚在笔记本上编译好tengine,这篇就先记录一下tengine在windows上的编译过程。

环境准备

虽然标题写的是用Clion通过cmake编译,但是在安装tengine的时候还是离不开Visual Studio的

  1. CMake >= 3.13
  2. Visual Studio >= 2015
  3. mingw64
  4. git

cmake和mingw64的bin目录需要添加到环境变量中

注:下载mingw64的时候,建议下载压缩包,不要下载online installer,要不然要安装到猴年马月去了。这里提供个下载链接
https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/sjlj/x86_64-8.1.0-release-posix-sjlj-rt_v6-rev0.7z/download

构建Tengine-lite

下载tengine,切换到tengine-lite分支

git clone https://github.com/OAID/Tengine.git  tengine-lite

然后使用"x86 Native Tools Command Prompt for VS 201x" 或者 "x64 Native Tools Command Prompt for VS 201x"进行构建,这两个工具在开始菜单都能找到

然后安装tengine给的步骤输入指令

# 把cmake添加到环境变量中
set PATH=X:/your/cmake/bin;%PATH% 
 
# 切换到tengine的下载目录
cd /d X:/your/downloaded/Tengine  

# 新建build文件夹,切换到build目录
mkdir build  
cd build  

# VS2017执行
cmake.exe -G "Visual Studio 15 2017 Win64" -DTENGINE_OPENMP=OFF -DTENGINE_BUILD_EXAMPLES=OFF ..
# VS2019执行
::cmake.exe -G "Visual Studio 16 2019" -A x64 -DTENGINE_OPENMP=OFF ..

# cmake构建,并安装
cmake.exe --build . --parallel 8
cmake.exe --build . --target install

到此C语言CPU版本的tengine就构建成功了,这里我们默认构建的是release版本。

在构建的过程中,尝试启用编译C++API与VULKAN,结果失败了,大致看了一下原因是说pthread的头文件没有找到,说明windows的支持还并不是特别完善。具体原因在后续的测评的文章里再探究。(实际开发谁用windows /狗头)

此时build/install下生成了includelib目录,我们将这两个目录及文件复制到我们自己的工程下即可。

项目实践

安装Clion,新建一个C++可执行文件的项目

配置工具链

image.png

配置CMake

image.png

项目结构如下

image.png

其中include目录下的文件是从下载的tengine-lite/examples/common/复制来的

CMakeLists文件的内容如下

cmake_minimum_required(VERSION 3.19)
project(tengine_demo)

add_executable(tengine_demo ./main.cpp src/tengine_operations.c)

# 包含目录
include_directories(${PROJECT_SOURCE_DIR}/include)

# 导入库文件
set(tengine-lib ${PROJECT_SOURCE_DIR}/lib/tengine-lite.lib
        ${PROJECT_SOURCE_DIR}/lib/tengine-lite.dll)
target_link_libraries(${PROJECT_NAME} ${tengine-lib})

main文件的作用是执行mobilenet分类网络,看官方给的流程代码感觉和TensorRT有些类似,计算图的流程的创建非常清晰,而且使用上又像NCNN方便。问题就是使用的是c语言,不是面向对象的,因此要记一些常用的api函数,不能通过对象直接调用。

main文件代码我将官方的文件进行了删减,主要是想把流程写清楚,在实际使用的时候,还需要做每一个步骤的情况判定,代码如下

#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "common.h"
#include "c_api.h"
#include "tengine_operations.h"

#define DEFAULT_IMG_H 224
#define DEFAULT_IMG_W 224
#define DEFAULT_SCALE1 1.f
#define DEFAULT_SCALE2 1.f
#define DEFAULT_SCALE3 1.f
#define DEFAULT_MEAN1 104.007
#define DEFAULT_MEAN2 116.669
#define DEFAULT_MEAN3 122.679
#define DEFAULT_LOOP_COUNT 1
#define DEFAULT_THREAD_COUNT 1
#define DEFAULT_CPU_AFFINITY 255

int tengine_classify(const char* model_file, const char* image_file, int img_h, int img_w, const float* mean,
                     const float* scale, int loop_count, int num_thread, int affinity)
{
    /* set runtime options */
    struct options opt;
    opt.num_thread = num_thread;
    opt.cluster = TENGINE_CLUSTER_ALL;
    opt.precision = TENGINE_MODE_FP32;
    opt.affinity = affinity;

    /* inital tengine */
    init_tengine();
    /* create graph, load tengine model xxx.tmfile */
    graph_t graph = create_graph(NULL, "tengine", model_file);

    /* set the shape, data buffer of input_tensor of the graph */
    int img_size = img_h * img_w * 3;
    int dims[] = {1, 3, img_h, img_w};    // nchw
    float* input_data = ( float* )malloc(img_size * sizeof(float));

    tensor_t input_tensor = get_graph_input_tensor(graph, 0, 0);

    set_tensor_shape(input_tensor, dims, 4);

    set_tensor_buffer(input_tensor, input_data, img_size * 4);

    /* prerun graph, set work options(num_thread, cluster, precision) */
    prerun_graph_multithread(graph, opt);

    /* prepare process input data, set the data mem to input tensor */
    get_input_data(image_file, input_data, img_h, img_w, mean, scale);

    run_graph(graph, 1);

    /* get the result of classification */
    tensor_t output_tensor = get_graph_output_tensor(graph, 0, 0);
    float* output_data = ( float* )get_tensor_buffer(output_tensor);
    int output_size = get_tensor_buffer_size(output_tensor) / sizeof(float);

    print_topk(output_data, output_size, 5);

    /* release tengine */
    free(input_data);
    postrun_graph(graph);
    destroy_graph(graph);
    release_tengine();

    return 0;
}

int main()
{
    int loop_count = DEFAULT_LOOP_COUNT;
    int num_thread = DEFAULT_THREAD_COUNT;
    int cpu_affinity = DEFAULT_CPU_AFFINITY;
    std::string model_file = "./model/mobilenet.tmfile";
    std::string image_file = "E:/000000000785.jpg";
    int img_h = DEFAULT_IMG_H;
    int img_w = DEFAULT_IMG_W;
    float mean[3] = {-DEFAULT_MEAN1, -DEFAULT_MEAN2, -DEFAULT_MEAN3};
    float scale[3] = {DEFAULT_SCALE1, DEFAULT_SCALE2, DEFAULT_SCALE3};

    if (tengine_classify(model_file.c_str(), image_file.c_str(), img_h, img_w,
                         mean, scale, loop_count, num_thread, cpu_affinity) < 0)
        return -1;

    return 0;
}

最后使用cmake构建项目,使用clion直接运行项目,需要注意的是,我们需要将model/model_name.tmfile 也放入到cmake的build目录下才能让程序加载模型文件

在github上可以搜到的关于tengine-lite的项目太少,搜索tengine倒是有很多,不过还要人眼过滤掉隔壁alibaba的项目,所以放一下本篇文章的项目链接https://github.com/shaoeric/tengine-lite-classification-demo

本期笔记就写这些,等看一看源码之后再去做做源码解读和上手

原文链接:https://zhuanlan.zhihu.com/p/375906721
作者:闪电侠的右手

推荐阅读

更多Tengine相关内容请关注Tengine-边缘AI推理框架专栏。
推荐阅读
关注数
3391
内容数
68
Tengine是一款轻量级模块化高性能的神经网络推理引擎 ;欢迎体验Tengine,[链接] 《Tengine开发者入门资料包》[链接]
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息