1. 程式人生 > 其它 >Window下搭建Tensorflow的C++環境

Window下搭建Tensorflow的C++環境

技術標籤:c++python深度學習tensorflow

參考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 [email protected]@@[email protected]\n")
    # 下面兩個就是複製的錯誤資訊
    def_fp.write("\t [email protected]@@[email protected]@[email protected]@[email protected]@@Z\n")
    def_fp.write("\t [email protected]@@[email protected]\n")

重新編譯DLL,標頭檔案(雖然很麻煩,但是還是得做啊)

4.3 有太多的錯誤導致IntelliSense引擎無法正常工作,其中有些錯誤無法在編輯器

解決方式:在專案->屬性->配置屬性->C/C+±>前處理器->前處理器定義中加入_XKEYCHECK_H就消失了

4.4 找不到tensorflow_cc.dll檔案

解決方式:將tensorflow_cc.dll檔案複製到x64/release資料夾下。

喜歡我的文章,還請大大們關注一波,當然可以直接訪問我的主頁:lixiaofei2yy.website