/ 环境搭建, TENSORFLOW, DEEPLEARNING

Window下搭建Tensorflow的C++环境

参考Tensorflow官网安装文章:https://www.tensorflow.org/install/source_windows?hl=zh-cn

一. 下载需要的软件

  • bazel:Google 的一款可再生的代码构建工具,类似于Cmake。使用scoop进行安装:scoop install bazel
  • python3.7:这里最好用pip 安装下必要的第三方包,比如tensorflow,kears,numpy等。
  • 下载官方源码:git clone https://github.com/tensorflow/tensorflow.git

二. 进行bazel源码编译

2.1 配置build

  • cd到源码目录:cd tensorflow-master
  • 通过在 TensorFlow 源代码树的根目录下运行以下命令来配置系统构建:python3 ./configure.py
  • 这里选择的是cpu版本的,每个配置的选择如下:
You have bazel 3.7.0 installed.
Please specify the location of python. [Default is C:\soft\python3.7.9\python3.exe]:


Found possible Python library paths:
  C:\soft\python3.7.9\lib\site-packages
Please input the desired Python library path to use.  Default is [C:\soft\python3.7.9\lib\site-packages]

Do you wish to build TensorFlow with ROCm support? [y/N]: n

Do you wish to build TensorFlow with CUDA support? [y/N]: n
No CUDA support will be enabled for TensorFlow.

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is /arch:AVX]:


Would you like to override eigen strong inline for some C++ compilation to reduce the compilation time? [Y/n]: y
Eigen strong inline overridden.

Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: n
Not configuring the WORKSPACE for Android builds.

Preconfigured Bazel build configs. You can use any of the below by adding "--config=<>" to your build command. See .bazelrc for more details.
        --config=mkl            # Build with MKL support.
        --config=mkl_aarch64    # Build with oneDNN support for Aarch64.
        --config=monolithic     # Config for mostly static monolithic build.
        --config=numa           # Build with NUMA support.
        --config=dynamic_kernels        # (Experimental) Build kernels into separate shared objects.
        --config=v2             # Build TensorFlow 2.x instead of 1.x.
Preconfigured Bazel build configs to DISABLE default on features:
        --config=noaws          # Disable AWS S3 filesystem support.
        --config=nogcp          # Disable GCP support.
        --config=nohdfs         # Disable HDFS support.
        --config=nonccl         # Disable NVIDIA NCCL support.

2.2 bazel编译

  • 修改bazel中间文件存储的路径(磁盘可用空间 Release 版本 >= 16G , Debug版本 >= 40G 编译的中间文件默认会放到 C:\用户\你的账号名\ _bazel_你的账号名 下. C 盘可能没有那么大的空间, 所以要改一下输出文件的路径),打开tensorflow文件夹,vim .bazelrc,在最后一行加上startup --output_user_root=D:/tf,如果不修改路径,可能会编译到一半就卡死。

  • bazel编译动态链接库命令(这里加上使用的最大内存):
     bazel build --config=opt //tensorflow:tensorflow_cc.dll --local_ram_resources=1024
    
  • 编译的过程可能会很长,千万不要以为有问题就Ctrl C了(分2个过程:下中间资源+编译),编译完成后会出现

     Build completed successfully
    
  • 编译好的库文件在tensorflow-master\bazel-bin\tensorflow目录下,分别是tensorflow_cc.dlltensorflow_cc.dll.if.lib

  • bazel编译头文件命令:

     bazel build --config=opt //tensorflow:install_headers --local_ram_resources=1024
    
  • 编译好的头文件在tensorflow-master\bazel-bin\tensorflow\include目录下。

三. 新建项目测试

注意:

​ 1. 这里编译的是tensorflow的release版本,因此构建项目的时候把环境从debug变成release

​ 2. 在新建项目属性表(这里无论是opencv还是tensorflow)中,要选择release版本的x64(64位)

  • 新建一个项目
  • 在项目中新建一个文件夹存放之前编译好的头文件,库文件,具体结构如下所示
├── tf_test// 整个项目
	├── x64 // 这里是生成解决方案得到的
	├── tf // 这里存放所有编译好的文件
    	├──bin // 存放dll动态库文件
        	├──tensorflow_cc.dll
        ├──lib // 存放静态库文件
        	├──tensorflow_cc.lib
        ├──include // 直接是tensorflow编译好的include目录
    ├──main.cpp
  • 属性管理器 —— Release X64 —— 添加新项目属性表(如果代码中还需要添加opencv库的可以参考本人另一篇博客

    • VC++目录中的包含目录中添加:D:tf_test\tf\include

    • VC++目录中的库目录中添加:D:tf_test\tf\lib
    • 链接器——输入——附加依赖项中添加:tensorflow_cc.lib
  • 选择项目为release和x64平台。

  • 使用以下代码进行测试

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/opencv.hpp>
#include"tensorflow/core/public/session.h"
#include"tensorflow/core/platform/env.h"

using namespace std;
using namespace tensorflow;
using namespace cv;

int main()
{
    const string model_path = "D:\\code\\yinbao_face\\live.pb";
    const string image_path = "0.jpg";


    Mat img = imread(image_path);
    cvtColor(img, img, COLOR_BGR2RGB);
    resize(img, img, Size(112, 112), 0, 0, INTER_NEAREST);
    int height = img.rows;
    int width = img.cols;
    int depth = img.channels();

    // 图像预处理
    img = (img - 0) / 255.0;
   // img.convertTo(img, CV_32FC3, 1.0 / 255, 0);

    // 取图像数据,赋给tensorflow支持的Tensor变量中
    const float* source_data = (float*)img.data;
    Tensor input_tensor(DT_FLOAT, TensorShape({ 1, height, width, 3 }));
    auto input_tensor_mapped = input_tensor.tensor<float, 4>();

    for (int i = 0; i < height; i++) {
        const float* source_row = source_data + (i * width * depth);
        for (int j = 0; j < width; j++) {
            const float* source_pixel = source_row + (j * depth);
            for (int c = 0; c < depth; c++) {
                const float* source_value = source_pixel + c;
                input_tensor_mapped(0, i, j, c) = *source_value;
                //printf("%d");
            }
        }
    }

    Session* session;

    Status status = NewSession(SessionOptions(), &session);
    if (!status.ok()) {
        cerr << status.ToString() << endl;
        return -1;
    }
    else {
        cout << "Session created successfully" << endl;
    }
    GraphDef graph_def;
    Status status_load = ReadBinaryProto(Env::Default(), model_path, &graph_def);
    if (!status_load.ok()) {
        cerr << status_load.ToString() << endl;
        return -1;
    }
    else {
        cout << "Load graph protobuf successfully" << endl;
    }

    // 将graph加载到session
    Status status_create = session->Create(graph_def);
    if (!status_create.ok()) {
        cerr << status_create.ToString() << endl;
        return -1;
    }
    else {
        cout << "Add graph to session successfully" << endl;
    }

    cout << input_tensor.DebugString() << endl; //打印输入
    vector<pair<string, Tensor>> inputs = {
        { "input_1:0", input_tensor },  //input_1:0为输入节点名
    };

    // 输出outputs
    vector<Tensor> outputs;
    vector<string> output_nodes;
    output_nodes.push_back("output_1:0");  //输出有多个节点的话就继续push_back

    double start = clock();
    // 运行会话,最终结果保存在outputs中
    Status status_run = session->Run({ inputs }, { output_nodes }, {}, &outputs);
    Tensor boxes = move(outputs.at(0));
    cout << boxes.DebugString() << endl; //打印输出

    double end = clock();
    cout << "time = " << (end - start) << "\n";
    if (!status_run.ok()) {
        cerr << status_run.ToString() << endl;
        return -1;
    }
    else {
        //cout << "Run session successfully" << endl;
    }
}

四. 测试中出现的问题

4.1 生成解决方案的时候报错无法打开包括文件:

解决方式:在本地的通过python pip安装后的tensorflow文件夹中(C:\soft\python3.7.9\Lib\site-packages\tensorflow\include)将google文件夹复制到D:tf_test\tf\include下面,即可解决

4.2 生成解决方案的时候报错Link1120:

解决方式:将vs2019上报错信息复制,cd到tensorflow-master\tensorflow\tools\def_file_filter(这里的tensorflow-master是自己下载tensorflow源码的地方),编辑def_file_filter.py.tpl文件:

# Header for the def file. (找到这一行代码)
    if args.target:
    def_fp.write("LIBRARY " + args.target + "\n")
    def_fp.write("EXPORTS\n")
    def_fp.write("\t ??1OpDef@tensorflow@@UEAA@XZ\n")
    # 下面两个就是复制的错误信息
    def_fp.write("\t ?NewSession@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@PEAPEAVSession@1@@Z\n")
    def_fp.write("\t ??0SessionOptions@tensorflow@@QEAA@XZ\n")

重新编译DLL,头文件(虽然很麻烦,但是还是得做啊)

4.3 有太多的错误导致IntelliSense引擎无法正常工作,其中有些错误无法在编辑器

解决方式:在项目->属性->配置属性->C/C++->预处理器->预处理器定义中加入_XKEYCHECK_H就消失了

4.4 找不到tensorflow_cc.dll文件

解决方式:将tensorflow_cc.dll文件复制到x64/release文件夹下。