如何啟用Halide后端以提高效率

2018-10-18 10:20 更新

介紹

本教程指導(dǎo)如何使用Halide語言后端在OpenCV深度學(xué)習(xí)模塊中運(yùn)行模型。Halide是一個開源項目,讓我們以易讀的格式編寫圖像處理算法,根據(jù)具體設(shè)備計劃計算,并以相當(dāng)好的效率進(jìn)行評估。

Halide項目的官方網(wǎng)站:http : //halide-lang.org/。

最新的效率比較:https//github.com/opencv/opencv/wiki/DNN-效率

要求

LLVM編譯器

注意
LLVM編譯可能需要很長時間。
  • http://releases.llvm.org/4.0.0/llvm-4.0.0.src.tar.xz下載LLVM源代碼。打開包裝 讓llvm_root是源代碼的根目錄。
  • 創(chuàng)建目錄llvm_root / tools / clang
  • 下載Clang與LLVM相同的版本。在我們的例子中,它將來自http://releases.llvm.org/4.0.0/cfe-4.0.0.src.tar.xz。將其打包成llvm_root / tools / clang。請注意,它應(yīng)該是Clang源代碼的根目錄。
  • 在Linux上構(gòu)建LLVM
    cd llvm_root
    mkdir build && cd build
    cmake -DLLVM_ENABLE_TERMINFO = OFF -DLLVM_TARGETS_TO_BUILD =“X86”-DLLVM_ENABLE_ASSERTIONS = ON -DCMAKE_BUILD_TYPE = Release ..
    make -j4
  • 在Windows上構(gòu)建LLVM(開發(fā)??者命令提示符)
    mkdir \\ path-to-llvm-build \\ && cd \\ path-to-llvm-build \\
    cmake.exe -DLLVM_ENABLE_TERMINFO = OFF -DLLVM_TARGETS_TO_BUILD = X86 -DLLVM_ENABLE_ASSERTIONS = ON -DCMAKE_BUILD_TYPE = Release -DCMAKE_INSTALL_PREFIX = \\ path-to-llvm-install \\ -G“Visual Studio 14 Win64”\\ path-to-llvm-src \\
    MSBuild.exe / m:4 / t:Build / p:Configuration = Release。\\ INSTALL.vcxproj
注意
\\path-to-llvm-build\\并且\\path-to-llvm-install\\是不同的目錄。

Halide language.

git clone https://github.com/halide/Halide.git
  • 在Linux上構(gòu)建Halide
cd halo_root
mkdir build && cd build
cmake -DLLVM_DIR = llvm_root / build / lib / cmake / llvm -DCMAKE_BUILD_TYPE = Release -DLLVM_VERSION = 40 -DWITH_TESTS = OFF -DWITH_APPS = OFF -DWITH_TUTORIALS = OFF ..
make -j4
  • 在Windows上構(gòu)建Halide(開發(fā)者命令提示符)
cd halo_root
mkdir build && cd build
cmake.exe -DLLVM_DIR = \\ path-to-llvm-install \\ lib \\ cmake \\ llvm -DLLVM_VERSION = 40 -DWITH_TESTS = OFF -DWITH_APPS = OFF -DWITH_TUTORIALS = OFF -DCMAKE_BUILD_TYPE = Release -G“Visual Studio 14 Win64“..
MSBuild.exe / m:4 / t:Build / p:Configuration = Release。\\ ALL_BUILD.vcxproj

用Halide后端構(gòu)建OpenCV

構(gòu)建OpenCV時,添加以下配置標(biāo)志:

  • ENABLE_CXX11 - 啟用C ++ 11標(biāo)準(zhǔn)
  • WITH_HALIDE - 啟用鹵化物連接
  • HALIDE_ROOT_DIR - Halide構(gòu)建目錄的路徑

Sample

// Sample of using Halide backend in OpenCV deep learning module.
// Based on caffe_googlenet.cpp.
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace cv::dnn;
#include <fstream>
#include <iostream>
#include <cstdlib>
/* Find best class for the blob (i. e. class with maximal probability) */
static void getMaxClass(const Mat &probBlob, int *classId, double *classProb)
{
    Mat probMat = probBlob.reshape(1, 1); //reshape the blob to 1x1000 matrix
    Point classNumber;
    minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
    *classId = classNumber.x;
}
static std::vector<std::string> readClassNames(const char *filename = "synset_words.txt")
{
    std::vector<std::string> classNames;
    std::ifstream fp(filename);
    if (!fp.is_open())
    {
        std::cerr << "File with classes labels not found: " << filename << std::endl;
        exit(-1);
    }
    std::string name;
    while (!fp.eof())
    {
        std::getline(fp, name);
        if (name.length())
            classNames.push_back( name.substr(name.find(' ')+1) );
    }
    fp.close();
    return classNames;
}
int main(int argc, char **argv)
{
    std::string modelTxt = "train_val.prototxt";
    std::string modelBin = "squeezenet_v1.1.caffemodel";
    std::string imageFile = (argc > 1) ? argv[1] : "space_shuttle.jpg";
    Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
    if (net.empty())
    {
        std::cerr << "Can't load network by using the following files: " << std::endl;
        std::cerr << "prototxt:   " << modelTxt << std::endl;
        std::cerr << "caffemodel: " << modelBin << std::endl;
        std::cerr << "SqueezeNet v1.1 can be downloaded from:" << std::endl;
        std::cerr << "https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1" << std::endl;
        exit(-1);
    }
    Mat img = imread(imageFile);
    if (img.empty())
    {
        std::cerr << "Can't read image from the file: " << imageFile << std::endl;
        exit(-1);
    }
    if (img.channels() != 3)
    {
        std::cerr << "Image " << imageFile << " isn't 3-channel" << std::endl;
        exit(-1);
    }
    resize(img, img, Size(227, 227));                // SqueezeNet v1.1 predict class by 3x227x227 input image.
    Mat inputBlob = blobFromImage(img, 1.0, Size(), Scalar(), false);  // Convert Mat to 4-dimensional batch.
    net.setInput(inputBlob);                         // Set the network input.
    net.setPreferableBackend(DNN_BACKEND_HALIDE);    // Tell engine to use Halide where it possible.
    Mat prob = net.forward("prob");                  // Compute output.
    int classId;
    double classProb;
    getMaxClass(prob, &classId, &classProb);         // Find the best class.
    std::vector<std::string> classNames = readClassNames();
    std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
    std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
    return 0;
} //main

說明

從SqueezeNet倉庫下載Caffe模型:train_val.prototxtsqueezenet_v1.1.caffemodel。

還需要使用名稱為ILSVRC2012類的文件:synset_words.txt。

將這些文件放入此程序示例的工作目錄中。

  1. 使用.prototxt和.caffemodel文件的路徑讀取并初始化網(wǎng)絡(luò)
        Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
    
  2. 檢查網(wǎng)絡(luò)是否已成功讀取
        if (net.empty())
        {
            std::cerr << "Can't load network by using the following files: " << std::endl;
            std::cerr << "prototxt:   " << modelTxt << std::endl;
            std::cerr << "caffemodel: " << modelBin << std::endl;
            std::cerr << "SqueezeNet v1.1 can be downloaded from:" << std::endl;
            std::cerr << "https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1" << std::endl;
            exit(-1);
        }
  3. 讀取輸入圖像并轉(zhuǎn)換為四維Blob,SqueezeNet v1.1可以接受
        Mat img = imread(imageFile);
        if (img.empty())
        {
            std::cerr << "Can't read image from the file: " << imageFile << std::endl;
            exit(-1);
        }
        if (img.channels() != 3)
        {
            std::cerr << "Image " << imageFile << " isn't 3-channel" << std::endl;
            exit(-1);
        }
        resize(img, img, Size(227, 227));                // SqueezeNet v1.1 predict class by 3x227x227 input image.
        Mat inputBlob = blobFromImage(img, 1.0, Size(), Scalar(), false);  // Convert Mat to 4-dimensional batch.
  4. 將blob傳遞到網(wǎng)絡(luò)
        net.setInput(inputBlob);                         // Set the network input.
    
  5. 為其實(shí)現(xiàn)的層啟用Halide后端
        net.setPreferableBackend(DNN_BACKEND_HALIDE);    // Tell engine to use Halide where it possible.
    
  6. Make forward pass
    • 記住,初始化之后的第一個向前傳遞需要相當(dāng)多的時間來實(shí)現(xiàn)下一個。這是因為第一次調(diào)用時Halide管道的運(yùn)行時編譯。
        Mat prob = net.forward("prob");                  // Compute output.
  7. 確定最好的班級
  8.     int classId;
        double classProb;
        getMaxClass(prob, &classId, &classProb);         // Find the best class.
  9. 打印結(jié)果
        std::vector<std::string> classNames = readClassNames();
        std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
        std::cout << "Probability: " << classProb * 100 << "%" << std::endl;

對于我們的圖像我們得到:

Best class: #812 'space shuttle'

Probability: 97.9812%


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號