在嘗試用 LazyNet 時,由於原作者提供的OpenCV和OpenBLAS版本和我的環境不一樣,考慮自行配置依賴。
OpenCV源碼編譯的文章很多,這里主要說一下OpenBLAS的編譯。
cblas_sgemm crash
基於VS2017的MSVC編譯器,編譯安裝openblas develop分支最新版,發現 LazyNet 代碼有crash(access violation),而在Linux(ubuntu16.04,G++/Clang++-8)則運行正常。剝離出來的復現問題的最小化代碼見下方,解決辦法是用clang-cl(Windows下和MSVC兼容的clang編譯器)重新編譯OpenBLAS,討論帖在此。
#include <stdio.h>
extern "C" {
#include <cblas.h>
}
int main() {
printf("OpenBLAS config info:\n%s\n", openblas_get_config());
#if 1 // will cause crash on VS2017 x64 with OpenBLAS latest
const int M = 16;
const int N = 676;
const int K = 27;
#else // won't crash
const int M = 4;
const int N = 2;
const int K = 3;
#endif
const float alpha = 1.0f;
const float beta = 0.f;
int lda = K;
int ldb = N;
int ldc = N;
float A[M*K];
float B[K*N];
float C[M*N];
cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, M, N, K, alpha, A, lda, B,
ldb, beta, C, ldc);
return 0;
}
clang-cl編譯OpenBLAS步驟
盡管 OpenBLAS 官方 wiki 頁面 How to use OpenBLAS in Microsoft Visual Studio 已經貼出了具體步驟,不過一開始我並沒有去翻看此文檔,想當然的認為CMake + VS2017即可。實踐下來發現我並不需要fortran(用不到LAPACK),所用步驟如下:
1. 安裝依賴軟件
Visual Studio 2017
我沒有勾選里面的Clang。后續用conda裝。
CMake
我手動從官網下載的二進制包。conda安裝的cmake似乎不帶cmake-gui,查看CMakeCache的時候不方便。
Ninja
因為不用fortran(flang)編譯,因此不必更新為kitware-ninja,常規版本即可。
conda安裝的
我用的Miniconda,你用Anaconda也行,反正是用里面的conda作為包管理工具。注意conda並非只能安裝Python的包(甚至pip也能裝cmake,不過個人不喜歡這么做)。
首先配置conda源,在GitBash中編輯~/.condarc
channels:
- conda-forge
- defaults
show_channel_urls: true
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
其次執行如下命令:
conda update -n base conda
conda install -y clangdev perl
2. 編譯安裝
下載源碼
cd /d/dev
#git clone https://gitee.com/aczz/OpenBLAS
git clone https://gitee.com/xianyi/OpenBLAS
cd OpenBLAS
git checkout develop
寫構建腳本
mkdir build
vim build/clang-cl.bat
build/clang-cl.bat
內容如下:
@echo off
set "LIB=%CONDA_INSTALL_LOCN%\Library\lib;%LIB%"
set "CPATH=%CONDA_INSTALL_LOCN%\Library\include;%CPATH%"
set BUILD_DIR="clang-cl"
if not exist %BUILD_DIR% mkdir %BUILD_DIR%
cd %BUILD_DIR%
cmake ../.. -G "Ninja" -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER=clang-cl -DBUILD_WITHOUT_LAPACK=yes -DDYNAMIC_ARCH=ON -DCMAKE_BUILD_TYPE=Release
cd ..
執行構建和安裝
"c:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvars64.bat"
cd build
clang-cl.bat
cmake --build . --config Release
cmake --install . --prefix d:/lib/openblas/clang-cl/x64 -v
3. 使用OpenBLAS
這里主要說一下 CMake 里設置 OpenBLAS:實測可用的例子:
# OpenBLAS_DIR 指向包含OpenBLASConfig.cmake的目錄
set(OpenBLAS_DIR "D:/lib/openblas/clang-cl/x64/share/cmake/OpenBLAS")
find_package(OpenBLAS REQUIRED)
add_executable(lazynet
${lazynet_srcs}
${lazynet_incs}
)
target_include_directories(lazynet
PUBLIC include
${OpenBLAS_INCLUDE_DIRS}
)
set(lazynet_dep_libs ${OpenCV_LIBS} ${OpenBLAS_LIBRARY})
if(UNIX)
list(APPEND lazynet_dep_libs pthread)
endif()
注意點:
- 不要用
OpenBLAS_LIBRARIES
變量
打印出來它的值為空,而不是像OpenBLASConfig.cmake
的注釋中寫的那樣,“和OpenBLAS_LIBRARIY相同”
- 不要信
FindBLAS.cmake
文件
盡管CMake(我用的3.17.1)安裝目錄下提供了FindBLAS.cmake
文件,看似提供了各種BLAS的查找功能,但就OpenBLAS來說,在Windows下還不如手動設定;在Linux下僅對於apt安裝的openblas(版本通常很老)能找到庫文件,但並不提供頭文件查找目錄,需要自行設定:
set(BLA_VENDOR "OpenBLAS")
find_package(BLAS REQUIRED)
set(OpenBLAS_INCLUDE_DIRS "/usr/include/openblas")
set(OpenBLAS_LIBRARY ${BLAS_LIBRARIES})
而手動編譯的openblas則並不能被很優雅的找到。因而,請忽略FindBLAS.cmake
這一文件。
- 自行編譯的openblas,在Linux下使用時,需要額外鏈接pthread庫