pytorch 矩阵相乘_编译PyTorch静态库
背景
眾所周知,PyTorch項目作為一個C++工程,是基于CMake進行構建的。然而當你想基于CMake來構建PyTorch靜態庫時,你會發現:
- 靜態編譯相關的文檔不全;
- CMake文件bug太多,其整體結構比較糟糕。
由于重構整體的CMake結構需要很多的人力,一時半會還看不到優雅的解決方案,因此在這里,Gemfield先寫篇文章來說明PyTorch的靜態編譯如何進行,以及各種注意事項。本文基于目前最新的PyTorch 1.7(在最新的master分支上也沒有問題)。
尤其是涉及到PyTorch靜態編譯重構的時候,還牽涉到代碼的重新設計。舉個例子,一些模塊的注冊機制是依賴全局對象初始化的,在靜態庫中,這樣的初始化邏輯并不會被鏈接(因為你的程序并沒有調用它),這就導致程序需要調用的內容并沒有被初始化。而為了解決這個問題引入的-Wl,--no-whole-archive,又導致編譯目標的體積變得極為龐大。當未來,若PyTorch官方倉庫為靜態編譯進行重構優化后,本文也就過時了(進而會被遷移到Gemfield的頹垣廢址專欄下)。
思緒再回來,本文以在Ubuntu 18.04 上進行目標為x86_64 Linux的構建為例,介紹使用CMake對PyTorch進行靜態編譯的2種最小尺度(這種最小尺度的定義是:不更改pytorch自身代碼、不使用CMake文件中intern的開關、使得libtorch能夠進行模型的前向推理、tensor的序列化反序列化、庫盡可能小):
- 最小尺度CPU版本;
- 最小尺度CUDA版本。
另外,在閱讀本文前,我們需要熟悉下幾個線性代數庫的名字。
BLAS (Basic Linear Algebra Subprograms),是一個常見線性代數操作的API規范,偏向底層,主要內容有:向量相加、標量相乘、點積、線性組合、矩陣相乘等。
LAPACK (Linear Algebra Package) 也是一個線性代數庫的規范. 基于BLAS規范,不同于BLAS的底層,LAPACK定位于高層。LAPACK定義矩陣分解的一些操作,如LU、LLt、QR、SVD、Schur,用來解決諸如找到矩陣的特征值、找到矩陣奇異值、求解線性方程組這樣的問題。
BLAS/LAPACK既然是API規范,就應該有相應的實現,常用的有這些:
- MKL,Intel Math Kernel Library。用于Intel處理器的(注意和MKL-DNN庫的區別,MKL-DNN是英特爾的一個獨立的神經網絡庫:MKL for Deep Neural Networks);
- ATLAS,Automatically Tuned Linear Algebra Software,多平臺的;
- OpenBLAS,多平臺的;
- Accelerate,蘋果macOS、iOS平臺上的;
- Eigen,這個庫只有頭文件,實現了BLAS和一部分LAPACK,集成到了PyTorch項目的thirdparty下;
- cuBLAS,NVIDIA的BLAS實現,基于NVIDIA的GPU硬件(此外還有cuFFT、cuRAND, cuSPARSE等);
- MAGMA,基于CUDA、HIP、 Intel Xeon Phi、OpenCL的BLAS/LAPACK實現;
還記得剛才提到過本文的目標是在Ubuntu 18.04上進行目標為x86_64 Linux的構建,這種情況下,我們必須要使用一個LAPACK實現:openblas、MKL或者Eigen。否則,運行時會報錯:“gels : Lapack library not found in compile time”。本文使用MKL,并實驗性質到介紹下如何使用Eigen。
CMake編譯開關
使用CMake進行構建時,我們主要是通過一些編譯開關來決定要編譯的模塊。這些編譯開關是在CMake文件中定義的變量,其值的來源主要有這幾種:
- 默認值;
- 用戶指定;
- 通過檢測系統環境獲得;
- 通過檢測軟件包的安裝情況獲得;
- 通過開關與開關之間的邏輯關系推導而來;
這些開關的值會影響:
- CMakeLists.txt中要添加的編譯單元;
- 編譯器、鏈接器的命令行參數;
- 代碼中的ifdef宏;
下面是一些主要的編譯開關的初始值,這些值初始值要么為OFF,要么為ON,要么為空。如下所示:
1,默認關閉的
2,默認打開的
3,默認為空的
CMake編譯開關的平臺修正
編譯開關的初始值并不是一成不變的,即使沒有用戶的手工指定,那么CMake也會通過檢測硬件環境、系統環境、包依賴來進行修改。比如下面這樣:
1,操作系統修正
2,CPU架構修正
3,軟件包依賴修正
4,用戶手工指令的修正
- 如果手工打開了USE_SYSTEM_LIBS,則:
- 如果設置環境變量BUILD_PYTORCH_MOBILE_WITH_HOST_TOOLCHAIN,則set(INTERN_BUILD_MOBILE ON),而INTERN_BUILD_MOBILE一旦打開,則:
5,CMake的配置
CMake的過程中會對系統環境進行檢查,主要用來檢測:
- 是否支持AVX2(perfkernels有依賴);
- 是否支持AVX512(fbgemm有依賴);
- 尋找BLAS實現,如果目標是Mobile平臺,使用Eigen;如果不是Mobile,則尋找MKL、openblas(找不到不會報錯,但程序運行時會提示:gels : Lapack library not found in compile time);
- Protobuf;
- python解釋器;
- NNPACK(NNPACK backend 是x86-64);
- OpenMP(是MKL-DNN的依賴);
- NUMA;
- pybind11;
- CUDA;
- ONNX;
- MAGMA(基于GPU等設備的blas/lapack實現);
- metal(蘋果生態);
- NEON(ARM生態,這里肯定是檢測不到相關的硬件了);
- MKL-DNN(Intel的深度學習庫);
- ATen parallel backend: NATIVE;
- Sleef(thirdparty下的三方庫);
- RT : /usr/lib/x86_64-linux-gnu/librt.so ;
- FFTW3 : /usr/lib/x86_64-linux-gnu/libfftw3.so;
- OpenSSL: /usr/lib/x86_64-linux-gnu/libcrypto.so;
- MPI;
CMake構建的時候會使用python腳本(tools/codegen/gen.py)生成一些cpp源文件,這個python腳本對yaml、dataclasses模塊有依賴,因此,在開始編譯前,你需要安裝這些包:
root@gemfield:~# pip3 install setuptools root@gemfield:~# pip3 install pyyaml root@gemfield:~# pip3 install dataclassesPyTorch官方預編譯動態庫的編譯選項
如果對官方編譯的庫所選用的編譯開關感興趣的話,可以使用如下的python命令獲得這些信息:
>>> print(torch.__config__.show()) PyTorch built with:- GCC 7.3- C++ Version: 201402- Intel(R) Math Kernel Library Version 2020.0.1 Product Build 20200208 for Intel(R) 64 architecture applications- Intel(R) MKL-DNN v1.5.0 (Git Hash e2ac1fac44c5078ca927cb9b90e1b3066a0b2ed0)- OpenMP 201511 (a.k.a. OpenMP 4.5)- NNPACK is enabled- CPU capability usage: AVX2- CUDA Runtime 10.1- NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_61,code=sm_61;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_37,code=compute_37- CuDNN 7.6.3- Magma 2.5.2- Build settings: BLAS=MKL, BUILD_TYPE=Release, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -DUSE_VULKAN_WRAPPER -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, USE_CUDA=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON, USE_STATIC_DISPATCH=OFF編譯最小尺度的CPU版本靜態庫(MKL后端)
在這個最小尺度的CPU版本里,Gemfield將會選擇MKL作為LAPACK的實現。此外,Gemfield將會首先禁用CUDA,這是自然而然的。其次Gemfield還要禁用caffe2(因為目的是編譯libtorch),這會連帶著禁用caffe2的op。整體要禁用的模塊還有:
- caffe2;
- 可執行文件;
- python;
- test;
- numa;
- 分布式(DISTRIBUTED);
- ROCM;
- GLOO;
- MPI;
- CUDA;
1,安裝MKL
既然選擇了MKL,第一步就是要安裝它。MKL使用的是ISSL授權(Intel Simplified Software License):
root@gemfield:~# wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB root@gemfield:~# apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB root@gemfield:~# echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list root@gemfield:~# apt update root@gemfield:~# apt install intel-mkl-64bit-2020.4-9122,使用CMake構建
命令如下:
cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=1 -DUSE_CUDA=OFF -DBUILD_CAFFE2=OFF -DBUILD_PYTHON:BOOL=OFF -DBUILD_CAFFE2_OPS=OFF -DUSE_DISTRIBUTED=OFF -DBUILD_TEST=OFF -DBUILD_BINARY=OFF -DBUILD_MOBILE_BENCHMARK=0 -DBUILD_MOBILE_TEST=0 -DUSE_ROCM=OFF -DUSE_GLOO=OFF -DUSE_LEVELDB=OFF -DUSE_MPI:BOOL=OFF -DBUILD_CUSTOM_PROTOBUF:BOOL=OFF -DUSE_OPENMP:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=Release -DPYTHON_EXECUTABLE:PATH=`which python3` -DCMAKE_INSTALL_PREFIX:PATH=../libtorch_cpu_mkl ../pytorch然后使用如下的命令進行編譯:
cmake --build . --target install -- "-j8"編譯成功后,生成的靜態庫有(23個,其中一個是鏈接文件):
lib/libprotobuf.a lib/libsleef.a lib/libclog.a lib/libcpuinfo.a lib/libnnpack.a lib/libasmjit.a lib/libmkldnn.a lib/libpytorch_qnnpack.a lib/libcaffe2_protos.a lib/libprotobuf-lite.a lib/libfbgemm.a lib/libc10.a lib/libpthreadpool.a lib/libtorch_cpu.a lib/libdnnl.a lib/libqnnpack.a lib/libprotoc.a lib/libXNNPACK.a lib/libtorch.a lib/libonnx_proto.a lib/libfmt.a lib/libonnx.a lib/libfoxi_loader.a或者你也想編譯Caffe2的話,就開啟BUILD_CAFFE2編譯開關:
cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=1 -DBUILD_CAFFE2=ON -DBUILD_CAFFE2_OPS=ON -DUSE_OPENMP=ON -DUSE_MKLDNN=ON -DUSE_GFLAGS=OFF -DUSE_GLOG=OFF -DUSE_CUDA=OFF -DBUILD_PYTHON:BOOL=OFF -DUSE_DISTRIBUTED=OFF -DBUILD_TEST=OFF -DBUILD_BINARY=OFF -DBUILD_MOBILE_BENCHMARK=0 -DBUILD_MOBILE_TEST=0 -DUSE_ROCM=OFF -DUSE_GLOO=OFF -DUSE_LEVELDB=OFF -DUSE_MPI:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=Release -DPYTHON_EXECUTABLE:PATH=`which python3` -DCMAKE_INSTALL_PREFIX:PATH=../libtorch_cpu_caffe2 ../pytorch生成的靜態庫有26個,除了上面的非caffe2版本,還多出來了perfkernel模塊生成的:
libCaffe2_perfkernels_avx.a libCaffe2_perfkernels_avx2.a libCaffe2_perfkernels_avx512.a這三個庫包含了如下的API,實現了一些FMA操作:
caffe2::EmbeddingLookupIdx_int32_t_float_float_false__avx2_fma caffe2::EmbeddingLookupIdx_int32_t_float_float_true__avx2_fma caffe2::EmbeddingLookupIdx_int32_t_half_float_false__avx2_fma caffe2::EmbeddingLookupIdx_int32_t_half_float_true__avx2_fma caffe2::EmbeddingLookupIdx_int32_t_uint8_t_float_false__avx2_fma caffe2::EmbeddingLookupIdx_int32_t_uint8_t_float_true__avx2_fma caffe2::EmbeddingLookupIdx_int64_t_float_float_false__avx2_fma caffe2::EmbeddingLookupIdx_int64_t_float_float_true__avx2_fma caffe2::EmbeddingLookupIdx_int64_t_half_float_false__avx2_fma caffe2::EmbeddingLookupIdx_int64_t_half_float_true__avx2_fma caffe2::EmbeddingLookupIdx_int64_t_uint8_t_float_false__avx2_fma caffe2::EmbeddingLookupIdx_int64_t_uint8_t_float_true__avx2_fma caffe2::EmbeddingLookup_int32_t_float_float_false__avx2_fma caffe2::EmbeddingLookup_int32_t_float_float_true__avx2_fma caffe2::EmbeddingLookup_int32_t_half_float_false__avx2_fma caffe2::EmbeddingLookup_int32_t_half_float_true__avx2_fma caffe2::EmbeddingLookup_int32_t_uint8_t_float_false__avx2_fma caffe2::EmbeddingLookup_int32_t_uint8_t_float_true__avx2_fma caffe2::EmbeddingLookup_int64_t_float_float_false__avx2_fma caffe2::EmbeddingLookup_int64_t_float_float_true__avx2_fma caffe2::EmbeddingLookup_int64_t_half_float_false__avx2_fma caffe2::EmbeddingLookup_int64_t_half_float_true__avx2_fma caffe2::EmbeddingLookup_int64_t_uint8_t_float_false__avx2_fma caffe2::EmbeddingLookup_int64_t_uint8_t_float_true__avx2_fma caffe2::Fused8BitRowwiseEmbeddingLookupIdx_int32_t_uint8_t_float_false__avx2_fma caffe2::Fused8BitRowwiseEmbeddingLookupIdx_int64_t_uint8_t_float_false__avx2_fma caffe2::Fused8BitRowwiseEmbeddingLookup_int32_t_uint8_t_float_false__avx2_fma caffe2::Fused8BitRowwiseEmbeddingLookup_int64_t_uint8_t_float_false__avx2_fma caffe2::TypedAxpy__avx2_fma caffe2::TypedAxpy__avx_f16c caffe2::TypedAxpyHalffloat__avx2_fma caffe2::TypedAxpyHalffloat__avx_f16c caffe2::TypedAxpy_uint8_float__avx2_fma此外,SELECTED_OP_LIST可以減少要編譯的OP,但本文不討論——因為Gemfield編譯的靜態庫要滿足不同模型的推理。
3,使用pytorch靜態庫(MKL后端版本)
如何讓自己的程序鏈接該靜態庫呢?由于MKL依賴openmp,因此編譯的命令行參數要打開(-fopenmp )。而PyTorch的代碼又需要依賴以下的MKL靜態庫:
/opt/intel/mkl/lib/intel64/libmkl_intel_lp64.a #/opt/intel/mkl/lib/intel64/libmkl_sequential.a /opt/intel/mkl/lib/intel64/libmkl_gnu_thread.a /opt/intel/mkl/lib/intel64/libmkl_core.a以及依賴系統上的這幾個共享庫:
/usr/lib/x86_64-linux-gnu/libpthread.so /usr/lib/x86_64-linux-gnu/libm.so /usr/lib/x86_64-linux-gnu/libdl.so因此你的程序需要鏈接這些庫(除了鏈接pytorch那二十幾個靜態庫外)才能完成編譯。感覺很復雜是吧?忘記這些吧,使用我們開源的libdeepvac庫吧。libdeepvac封裝了libtorch,提供更簡化的C++中使用PyTorch模型的方法。
編譯最小尺度的CPU版本靜態庫(Eigen后端)
在這個最小尺度的CPU版本里,Gemfield將會選擇Eigen來作為LAPACK的實現。使用Eigen來作為LAPACK實現的話,需要打開INTERN_USE_EIGEN_BLAS。看見INTERN前綴了吧,這提示我們不應該這樣來使用這個開關。并且由于在PyTorch中,Eigen是為mobile平臺而設計使用的,因此要想在x86_64 Linux使用,就需要改下pytorch倉庫中的CMake文件:一共2處。
1,修改PyTorch的CMake文件
第一處,修改cmake/Dependencies.cmake:
#if(NOT INTERN_BUILD_MOBILE) # set(AT_MKL_ENABLED 0) # set(AT_MKL_MT 0) # set(USE_BLAS 1) # if(NOT (ATLAS_FOUND OR OpenBLAS_FOUND OR MKL_FOUND OR VECLIB_FOUND OR GENERIC_BLAS_FOUND)) # message(WARNING "Preferred BLAS (" ${BLAS} ") cannot be found, now searching for a general BLAS library") # find_package(BLAS) # if(NOT BLAS_FOUND) # set(USE_BLAS 0) # endif() # endif() # # if(MKL_FOUND) # add_definitions(-DTH_BLAS_MKL) # if("${MKL_THREADING}" STREQUAL "SEQ") # add_definitions(-DTH_BLAS_MKL_SEQ=1) # endif() # if(MSVC AND MKL_LIBRARIES MATCHES ".*libiomp5md.lib.*") # add_definitions(-D_OPENMP_NOFORCE_MANIFEST) # set(AT_MKL_MT 1) # endif() # set(AT_MKL_ENABLED 1) # endif() if(INTERN_USE_EIGEN_BLAS)# Eigen BLAS for Mobileset(USE_BLAS 1)set(AT_MKL_ENABLED 0)include(${CMAKE_CURRENT_LIST_DIR}/External/EigenBLAS.cmake)list(APPEND Caffe2_DEPENDENCY_LIBS eigen_blas) endif()第二處,修改cmake/External/EigenBLAS.cmake:
root@gemfield:~# git diff cmake/External/EigenBLAS.cmake ......set(__EIGEN_BLAS_INCLUDED TRUE) - -if(NOT INTERN_BUILD_MOBILE OR NOT INTERN_USE_EIGEN_BLAS) +if(NOT INTERN_USE_EIGEN_BLAS)return()endif()此外,像MKL后端那樣,Gemfield要照例禁用CUDA、caffe2、caffe2的op。
2,使用CMake進行構建
命令如下(注意開啟了INTERN_USE_EIGEN_BLAS):
cmake -DINTERN_USE_EIGEN_BLAS=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=1 -DBUILD_CAFFE2=OFF -DBUILD_CAFFE2_OPS=OFF -DBUILD_PYTHON:BOOL=OFF -DUSE_DISTRIBUTED=OFF -DBUILD_TEST=OFF -DBUILD_BINARY=OFF -DBUILD_MOBILE_BENCHMARK=0 -DBUILD_MOBILE_TEST=0 -DUSE_ROCM=OFF -DUSE_GLOO=OFF -DUSE_CUDA=OFF -DUSE_LEVELDB=OFF -DUSE_MPI:BOOL=OFF -DBUILD_CUSTOM_PROTOBUF:BOOL=OFF -DUSE_OPENMP:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=Release -DPYTHON_EXECUTABLE:PATH=`which python3` -DCMAKE_INSTALL_PREFIX:PATH=../libtorch_cpu_eigen ../pytorch然后使用如下的命令進行編譯:
cmake --build . --target install -- "-j8"編譯出來的靜態庫如下所示(24個,注意多出來libeigen_blas.a):
lib/libprotobuf.a lib/libsleef.a lib/libclog.a lib/libcpuinfo.a lib/libeigen_blas.a lib/libnnpack.a lib/libasmjit.a lib/libmkldnn.a lib/libpytorch_qnnpack.a lib/libcaffe2_protos.a lib/libprotobuf-lite.a lib/libfbgemm.a lib/libc10.a lib/libpthreadpool.a lib/libtorch_cpu.a lib/libdnnl.a lib/libqnnpack.a lib/libprotoc.a lib/libXNNPACK.a lib/libtorch.a lib/libonnx_proto.a lib/libfmt.a lib/libonnx.a lib/libfoxi_loader.a3,使用pytorch靜態庫(Eigen后端版本)
和MKL后端不同,你的程序需要從鏈接MKL轉而去鏈接libeigen_blas.a,更簡單了。如果使用libdeepvac庫的話,這都是無感的。
和MKL后端的靜態庫進行了下粗略的性能比較,在6核intel處理器的系統上,對20個目標進行CNN+LSTM的計算下,MKL版本消耗了11秒,而Eigen版本消耗了20秒。所以還是推薦使用MKL。
編譯最小尺度的CUDA版本靜態庫(無MAGMA版本)
1,配置
相關的配置如下:
- 要編譯CUDA版本,必須啟用USE_CUDA;
- 另外,回落到CPU的時候,我們依然需要有對應的LAPACK實現,這里還是選擇MKL,安裝方法見前文;
- 還有一個地方需要注意:是否使用MAGMA。這里Gemfield先不使用。
2,CUDA架構
同CPU版本相比,編譯CUDA版本的最大不同就是要指定CUDA架構(開普勒、麥克斯韋、帕斯卡、圖靈、安培等)。要編譯特定CUDA架構的目標,需要給NVCC編譯器傳遞特定架構的號碼,如7.0。特定架構的號碼有兩種情況:PTX和非PTX。比如7.0 和 7.0 PTX。
非PTX版本是實際的二進制文件,只能做到主版本號兼容。比如compute capability 3.0 的編譯產物只能運行在compute-capability 3.x的架構上(開普勒架構),而不能運行在compute-capability 5.x (麥克斯韋) 或者 6.x (帕斯卡) 設備上。
而PTX版本編譯出來的是JIT的中間代碼,可以做到前向兼容——也就是舊設備的目標可以運行在新設備上。因為編譯的時候可以指定多個架構號碼,因此一個技巧就是,總是在最高的版本號上加上PTX,以獲得前向兼容,比如:3.5;5.0;5.2;6.0;6.1;7.0;7.5;7.5+PTX。
另外,在不兼容的CUDA設備上運行你的程序會出現“no kernel image is available for execution on the device”錯誤。編譯PyTorch的時候,這個CUDA架構號碼來自三種方式:
- 自動檢測本地機器上的設備號;
- 檢測不到,則使用默認的一組;
- 用戶通過TORCH_CUDA_ARCH_LIST環境變量指定。TORCH_CUDA_ARCH_LIST環境變量,比如TORCH_CUDA_ARCH_LIST="3.5 5.2 6.0 6.1+PTX",決定了要編譯的pytorch支持哪些cuda架構。支持的架構越多,最后的庫越大;
一些市面上常見顯卡的compute-capability號碼如下所示:
3,使用CMake進行構建
cmake命令如下(注意打開了USE_CUDA):
cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=1 -DUSE_CUDA=ON -DBUILD_CAFFE2=OFF -DBUILD_CAFFE2_OPS=OFF -DUSE_DISTRIBUTED=OFF -DBUILD_TEST=OFF -DBUILD_BINARY=OFF -DBUILD_MOBILE_BENCHMARK=0 -DBUILD_MOBILE_TEST=0 -DUSE_ROCM=OFF -DUSE_GLOO=OFF -DUSE_LEVELDB=OFF -DUSE_MPI:BOOL=OFF -DBUILD_PYTHON:BOOL=OFF -DBUILD_CUSTOM_PROTOBUF:BOOL=OFF -DUSE_OPENMP:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=Release -DPYTHON_EXECUTABLE:PATH=`which python3` -DCMAKE_INSTALL_PREFIX:PATH=../libtorch_cuda ../pytorch在CUDA版本中,CMake構建時還會檢測:
- -- CUDA detected: 10.2
- -- CUDA nvcc is: /usr/local/cuda/bin/nvcc
- -- CUDA toolkit directory: /usr/local/cuda
- -- cuDNN: v7.6.5 (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libcudnn.so)
- -- Autodetected CUDA architecture(s): 3.5;5.0;5.2;6.0;6.1;7.0;7.5;7.5+PTX;
- -- Found CUDA with FP16 support, compiling with torch.cuda.HalfTensor;
然后使用如下的命令進行編譯:
cmake --build . --target install -- "-j8"編譯出如下的靜態庫(26個):
libasmjit.a libc10.a libc10_cuda.a libcaffe2_protos.a libclog.a libcpuinfo.a libdnnl.a libfbgemm.a libfmt.a libfoxi_loader.a libmkldnn.a libnccl_static.a libnnpack.a libonnx.a libonnx_proto.a libprotobuf.a libprotobuf-lite.a libprotoc.a libpthreadpool.a libpytorch_qnnpack.a libqnnpack.a libsleef.a libtorch.a libtorch_cpu.a libtorch_cuda.a libXNNPACK.a可以看到相比CPU版本多出了libtorch_cuda.a、 libc10_cuda.a、libnccl_static.a這3個靜態庫。
4,使用pytorch靜態庫(CUDA版本)
和CPU版本類似,但是區別是還要鏈接NVIDIA的cuda運行時的庫(這部分是動態庫)。此外,如果你的程序初始化的時候報錯:“PyTorch is not linked with support for cuda devices”,說明你沒有whole_archive c10_cuda.a靜態庫。
如果你編譯自己程序的時候遇到了cannot find -lnvToolsExt、cannot find -lcudart這樣的錯誤,你還需要設置下環境變量讓鏈接器能夠找到cuda運行時的庫:
root@gemfield:~# export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/cuda-10.2/targets/x86_64-linux/lib/總之,你如果使用了libdeepvac封裝的話(需要打開USE_CUDA),就沒有這么多問題了。
5,性能
做了一個快速的不嚴謹的推理性能測試。使用了cuda版本后,還是之前的那個系統,還是之前那個測試任務(對20個目標進行CNN+LSTM的計算下),CUDA版本消耗了不到一秒。
最后
在你使用pytorch靜態庫的時候,或多或少還會遇到一些問題。但是,何必自討苦吃呢,使用我們封裝了libtorch的libdeepvac庫吧:
DeepVAC/libdeepvac?github.com總結
以上是生活随笔為你收集整理的pytorch 矩阵相乘_编译PyTorch静态库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 维吾尔族叫牛腩肉叫什么肉
- 下一篇: 文章采集伪原创工具_卓尔博通|如何把伪原