日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

pytorch 矩阵相乘_编译PyTorch静态库

發(fā)布時(shí)間:2024/10/12 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pytorch 矩阵相乘_编译PyTorch静态库 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

背景

眾所周知,PyTorch項(xiàng)目作為一個(gè)C++工程,是基于CMake進(jìn)行構(gòu)建的。然而當(dāng)你想基于CMake來構(gòu)建PyTorch靜態(tài)庫(kù)時(shí),你會(huì)發(fā)現(xiàn):

  • 靜態(tài)編譯相關(guān)的文檔不全;
  • CMake文件bug太多,其整體結(jié)構(gòu)比較糟糕。

由于重構(gòu)整體的CMake結(jié)構(gòu)需要很多的人力,一時(shí)半會(huì)還看不到優(yōu)雅的解決方案,因此在這里,Gemfield先寫篇文章來說明PyTorch的靜態(tài)編譯如何進(jìn)行,以及各種注意事項(xiàng)。本文基于目前最新的PyTorch 1.7(在最新的master分支上也沒有問題)。

尤其是涉及到PyTorch靜態(tài)編譯重構(gòu)的時(shí)候,還牽涉到代碼的重新設(shè)計(jì)。舉個(gè)例子,一些模塊的注冊(cè)機(jī)制是依賴全局對(duì)象初始化的,在靜態(tài)庫(kù)中,這樣的初始化邏輯并不會(huì)被鏈接(因?yàn)槟愕某绦虿]有調(diào)用它),這就導(dǎo)致程序需要調(diào)用的內(nèi)容并沒有被初始化。而為了解決這個(gè)問題引入的-Wl,--no-whole-archive,又導(dǎo)致編譯目標(biāo)的體積變得極為龐大。當(dāng)未來,若PyTorch官方倉(cāng)庫(kù)為靜態(tài)編譯進(jìn)行重構(gòu)優(yōu)化后,本文也就過時(shí)了(進(jìn)而會(huì)被遷移到Gemfield的頹垣廢址專欄下)。

思緒再回來,本文以在Ubuntu 18.04 上進(jìn)行目標(biāo)為x86_64 Linux的構(gòu)建為例,介紹使用CMake對(duì)PyTorch進(jìn)行靜態(tài)編譯的2種最小尺度(這種最小尺度的定義是:不更改pytorch自身代碼、不使用CMake文件中intern的開關(guān)、使得libtorch能夠進(jìn)行模型的前向推理、tensor的序列化反序列化、庫(kù)盡可能小):

  • 最小尺度CPU版本;
  • 最小尺度CUDA版本。

另外,在閱讀本文前,我們需要熟悉下幾個(gè)線性代數(shù)庫(kù)的名字。

BLAS (Basic Linear Algebra Subprograms),是一個(gè)常見線性代數(shù)操作的API規(guī)范,偏向底層,主要內(nèi)容有:向量相加、標(biāo)量相乘、點(diǎn)積、線性組合、矩陣相乘等。

LAPACK (Linear Algebra Package) 也是一個(gè)線性代數(shù)庫(kù)的規(guī)范. 基于BLAS規(guī)范,不同于BLAS的底層,LAPACK定位于高層。LAPACK定義矩陣分解的一些操作,如LU、LLt、QR、SVD、Schur,用來解決諸如找到矩陣的特征值、找到矩陣奇異值、求解線性方程組這樣的問題。

BLAS/LAPACK既然是API規(guī)范,就應(yīng)該有相應(yīng)的實(shí)現(xiàn),常用的有這些:

  • MKL,Intel Math Kernel Library。用于Intel處理器的(注意和MKL-DNN庫(kù)的區(qū)別,MKL-DNN是英特爾的一個(gè)獨(dú)立的神經(jīng)網(wǎng)絡(luò)庫(kù):MKL for Deep Neural Networks);
  • ATLAS,Automatically Tuned Linear Algebra Software,多平臺(tái)的;
  • OpenBLAS,多平臺(tái)的;
  • Accelerate,蘋果macOS、iOS平臺(tái)上的;
  • Eigen,這個(gè)庫(kù)只有頭文件,實(shí)現(xiàn)了BLAS和一部分LAPACK,集成到了PyTorch項(xiàng)目的thirdparty下;
  • cuBLAS,NVIDIA的BLAS實(shí)現(xiàn),基于NVIDIA的GPU硬件(此外還有cuFFT、cuRAND, cuSPARSE等);
  • MAGMA,基于CUDA、HIP、 Intel Xeon Phi、OpenCL的BLAS/LAPACK實(shí)現(xiàn);

還記得剛才提到過本文的目標(biāo)是在Ubuntu 18.04上進(jìn)行目標(biāo)為x86_64 Linux的構(gòu)建,這種情況下,我們必須要使用一個(gè)LAPACK實(shí)現(xiàn):openblas、MKL或者Eigen。否則,運(yùn)行時(shí)會(huì)報(bào)錯(cuò):“gels : Lapack library not found in compile time”。本文使用MKL,并實(shí)驗(yàn)性質(zhì)到介紹下如何使用Eigen。

CMake編譯開關(guān)

使用CMake進(jìn)行構(gòu)建時(shí),我們主要是通過一些編譯開關(guān)來決定要編譯的模塊。這些編譯開關(guān)是在CMake文件中定義的變量,其值的來源主要有這幾種:

  • 默認(rèn)值;
  • 用戶指定;
  • 通過檢測(cè)系統(tǒng)環(huán)境獲得;
  • 通過檢測(cè)軟件包的安裝情況獲得;
  • 通過開關(guān)與開關(guān)之間的邏輯關(guān)系推導(dǎo)而來;

這些開關(guān)的值會(huì)影響:

  • CMakeLists.txt中要添加的編譯單元;
  • 編譯器、鏈接器的命令行參數(shù);
  • 代碼中的ifdef宏;

下面是一些主要的編譯開關(guān)的初始值,這些值初始值要么為OFF,要么為ON,要么為空。如下所示:

1,默認(rèn)關(guān)閉的

  • ATEN_NO_TEST,是否編譯ATen test binaries;
  • BUILD_BINARY,Build C++ binaries;
  • BUILD_DOCS,Build Caffe2 documentation;
  • BUILD_CAFFE2_MOBILE,Build libcaffe2 for mobile,也就是在libcaffe2和libtorch mobile中選擇,目前已經(jīng)廢棄,默認(rèn)使用libtorch mobile;
  • CAFFE2_USE_MSVC_STATIC_RUNTIME,Using MSVC static runtime libraries;
  • BUILD_TEST,Build C++ test binaries (need gtest and gbenchmark);
  • BUILD_STATIC_RUNTIME_BENCHMARK,Build C++ binaries for static runtime benchmarks (need gbenchmark);
  • BUILD_TENSOREXPR_BENCHMARK,Build C++ binaries for tensorexpr benchmarks (need gbenchmark);
  • BUILD_MOBILE_BENCHMARK,Build C++ test binaries for mobile (ARM) targets(need gtest and gbenchmark);
  • BUILD_MOBILE_TEST,Build C++ test binaries for mobile (ARM) targets(need gtest and gbenchmark);
  • BUILD_JNI,Build JNI bindings;
  • BUILD_MOBILE_AUTOGRAD,Build autograd function in mobile build (正在開發(fā)中);
  • INSTALL_TEST,Install test binaries if BUILD_TEST is on;
  • USE_CPP_CODE_COVERAGE,Compile C/C++ with code coverage flags;
  • USE_ASAN,Use Address Sanitizer;
  • USE_TSAN,Use Thread Sanitizer;
  • CAFFE2_STATIC_LINK_CUDA,Statically link CUDA libraries;
  • USE_STATIC_CUDNN,Use cuDNN static libraries;
  • USE_KINETO,Use Kineto profiling library;
  • USE_FAKELOWP,Use FakeLowp operators;
  • USE_FFMPEG;
  • USE_GFLAGS;
  • USE_GLOG;
  • USE_LEVELDB;
  • USE_LITE_PROTO,Use lite protobuf instead of full;
  • USE_LMDB;
  • USE_PYTORCH_METAL,Use Metal for PyTorch iOS build;
  • USE_NATIVE_ARCH,Use -march=native;
  • USE_STATIC_NCCL;
  • USE_SYSTEM_NCCL,Use system-wide NCCL;
  • USE_NNAPI;
  • USE_NVRTC,Use NVRTC. Only available if USE_CUDA is on;
  • USE_OBSERVERS,Use observers module;
  • USE_OPENCL;
  • USE_OPENCV;
  • USE_PROF,Use profiling;
  • USE_REDIS;
  • USE_ROCKSDB;
  • USE_SNPE,使用高通的神經(jīng)網(wǎng)絡(luò)引擎;
  • USE_SYSTEM_EIGEN_INSTALL,Use system Eigen instead of the one under third_party;
  • USE_TENSORRT,Using Nvidia TensorRT library;
  • USE_VULKAN,Use Vulkan GPU backend;
  • USE_VULKAN_API,Use Vulkan GPU backend v2;
  • USE_VULKAN_SHADERC_RUNTIME,Use Vulkan Shader compilation runtime(Needs shaderc lib);
  • USE_VULKAN_RELAXED_PRECISION,Use Vulkan relaxed precision(mediump);
  • USE_ZMQ;
  • USE_ZSTD;
  • USE_MKLDNN_CBLAS,Use CBLAS in MKLDNN;
  • USE_TBB;
  • HAVE_SOVERSION,Whether to add SOVERSION to the shared objects;
  • USE_SYSTEM_LIBS,Use all available system-provided libraries;
  • USE_SYSTEM_CPUINFO,Use system-provided cpuinfo;
  • USE_SYSTEM_SLEEF,Use system-provided sleef;
  • USE_SYSTEM_GLOO,Use system-provided gloo;
  • USE_SYSTEM_FP16,Use system-provided fp16;
  • USE_SYSTEM_PTHREADPOOL,Use system-provided pthreadpool;
  • USE_SYSTEM_PSIMD,Use system-provided psimd;
  • USE_SYSTEM_FXDIV,Use system-provided fxdiv;
  • USE_SYSTEM_BENCHMARK,Use system-provided google benchmark;
  • USE_SYSTEM_ONNX,Use system-provided onnx;
  • USE_SYSTEM_XNNPACK,Use system-provided xnnpack。
  • 2,默認(rèn)打開的

  • BUILD_CUSTOM_PROTOBUF,Build and use Caffe2's own protobuf under third_party;
  • BUILD_PYTHON,Build Python binaries;
  • BUILD_CAFFE2,Master flag to build Caffe2;
  • BUILD_CAFFE2_OPS,Build Caffe2 operators;
  • BUILD_SHARED_LIBS,Build libcaffe2.so;
  • CAFFE2_LINK_LOCAL_PROTOBUF,If set, build protobuf inside libcaffe2.so;
  • COLORIZE_OUTPUT,Colorize output during compilation;
  • USE_CUDA;
  • USE_CUDNN;
  • USE_ROCM;
  • USE_FBGEMM,Use FBGEMM (quantized 8-bit server operators);
  • USE_METAL,Use Metal for Caffe2 iOS build;
  • USE_NCCL,須在UNIX上,且USE_CUDA 或USE_ROCM是打開的;
  • USE_NNPACK;
  • USE_NUMPY;
  • USE_OPENMP,Use OpenMP for parallel code;
  • USE_QNNPACK;Use QNNPACK (quantized 8-bit operators);
  • USE_PYTORCH_QNNPACK,Use ATen/QNNPACK (quantized 8-bit operators);
  • USE_VULKAN_WRAPPER,Use Vulkan wrapper;
  • USE_XNNPACK,
  • USE_DISTRIBUTED;
  • USE_MPI,Use MPI for Caffe2. Only available if USE_DISTRIBUTED is on;
  • USE_GLOO,Only available if USE_DISTRIBUTED is on;
  • USE_TENSORPIPE,Only available if USE_DISTRIBUTED is on;
  • ONNX_ML,Enable traditional ONNX ML API;
  • USE_NUMA;
  • USE_VALGRIND;
  • USE_MKLDNN;
  • BUILDING_WITH_TORCH_LIBS,Tell cmake if Caffe2 is being built alongside torch libs。
  • 3,默認(rèn)為空的

  • SELECTED_OP_LIST,Path to the yaml file that contains the list of operators to include for custom build. Include all operators by default;
  • OP_DEPENDENCY,Path to the yaml file that contains the op dependency graph for custom build。
  • CMake編譯開關(guān)的平臺(tái)修正

    編譯開關(guān)的初始值并不是一成不變的,即使沒有用戶的手工指定,那么CMake也會(huì)通過檢測(cè)硬件環(huán)境、系統(tǒng)環(huán)境、包依賴來進(jìn)行修改。比如下面這樣:

    1,操作系統(tǒng)修正

  • USE_DISTRIBUTED,如果不是Linux/Win32,則關(guān)閉;
  • USE_LIBUV,macOS上,且手工打開USE_DISTRIBUTED,則打開;
  • USE_NUMA,如果不是Linux,則關(guān)閉;
  • USE_VALGRIND,如果不是Linux,則關(guān)閉;
  • USE_TENSORPIPE,如果是Windows,則關(guān)閉;
  • USE_KINETO,如果是windows,則關(guān)閉;
  • 如果是構(gòu)建Android、iOS等移動(dòng)平臺(tái)上的libtorch,則:
  • set(BUILD_PYTHON OFF)set(BUILD_CAFFE2_OPS OFF)set(USE_DISTRIBUTED OFF)set(FEATURE_TORCH_MOBILE ON)set(NO_API ON)set(USE_FBGEMM OFF)set(USE_QNNPACK OFF)set(INTERN_DISABLE_ONNX ON)set(INTERN_USE_EIGEN_BLAS ON)set(INTERN_DISABLE_MOBILE_INTERP ON)

    2,CPU架構(gòu)修正

  • USE_MKLDNN,如果不是64位x86_64,則關(guān)閉;
  • USE_FBGEMM,如果不是64位x86_64,則關(guān)閉;如果不支持AVX512指令集,則關(guān)閉;
  • USE_KINETO,如果是手機(jī)平臺(tái),則關(guān)閉;
  • USE_GLOO,如果不是64位x86_64,則關(guān)閉;
  • 3,軟件包依賴修正

  • USE_DISTRIBUTED,在Windows上,如果找不到libuv,則關(guān)閉;
  • USE_GLOO,在Windows上,如果找不到libuv,則關(guān)閉;
  • USE_KINETO,如果沒有USE_CUDA,則關(guān)閉;
  • MKL相關(guān),不再贅述;
  • NNPACK家族相關(guān)的((QNNPACK, PYTORCH_QNNPACK, XNNPACK) ),不再贅述;
  • USE_BLAS,會(huì)被相關(guān)依賴修正;
  • USE_PTHREADPOOL,會(huì)被相關(guān)依賴修正;
  • USE_LAPACK,如果LAPACK包不能被找到,則關(guān)閉;且運(yùn)行時(shí)會(huì)導(dǎo)致出錯(cuò):“gels : Lapack library not found in compile time”;
  • 4,用戶手工指令的修正

    • 如果手工打開了USE_SYSTEM_LIBS,則:
    set(USE_SYSTEM_CPUINFO ON)set(USE_SYSTEM_SLEEF ON)set(USE_SYSTEM_GLOO ON)set(BUILD_CUSTOM_PROTOBUF OFF)set(USE_SYSTEM_EIGEN_INSTALL ON)set(USE_SYSTEM_FP16 ON)set(USE_SYSTEM_PTHREADPOOL ON)set(USE_SYSTEM_PSIMD ON)set(USE_SYSTEM_FXDIV ON)set(USE_SYSTEM_BENCHMARK ON)set(USE_SYSTEM_ONNX ON)set(USE_SYSTEM_XNNPACK ON)
    • 如果設(shè)置環(huán)境變量BUILD_PYTORCH_MOBILE_WITH_HOST_TOOLCHAIN,則set(INTERN_BUILD_MOBILE ON),而INTERN_BUILD_MOBILE一旦打開,則:
    #只有編譯caffe2 mobile的時(shí)候才是OFF,其它時(shí)候都是ON,也就是都會(huì)編譯ATen的op set(INTERN_BUILD_ATEN_OPS ON)set(BUILD_PYTHON OFF) set(BUILD_CAFFE2_OPS OFF) set(USE_DISTRIBUTED OFF) set(FEATURE_TORCH_MOBILE ON) set(NO_API ON) set(USE_FBGEMM OFF) set(USE_QNNPACK OFF) set(INTERN_DISABLE_ONNX ON) set(INTERN_USE_EIGEN_BLAS ON) set(INTERN_DISABLE_MOBILE_INTERP ON)

    5,CMake的配置

    CMake的過程中會(huì)對(duì)系統(tǒng)環(huán)境進(jìn)行檢查,主要用來檢測(cè):

    • 是否支持AVX2(perfkernels有依賴);
    • 是否支持AVX512(fbgemm有依賴);
    • 尋找BLAS實(shí)現(xiàn),如果目標(biāo)是Mobile平臺(tái),使用Eigen;如果不是Mobile,則尋找MKL、openblas(找不到不會(huì)報(bào)錯(cuò),但程序運(yùn)行時(shí)會(huì)提示:gels : Lapack library not found in compile time);
    • Protobuf;
    • python解釋器;
    • NNPACK(NNPACK backend 是x86-64);
    • OpenMP(是MKL-DNN的依賴);
    • NUMA;
    • pybind11;
    • CUDA;
    • ONNX;
    • MAGMA(基于GPU等設(shè)備的blas/lapack實(shí)現(xiàn));
    • metal(蘋果生態(tài));
    • NEON(ARM生態(tài),這里肯定是檢測(cè)不到相關(guān)的硬件了);
    • MKL-DNN(Intel的深度學(xué)習(xí)庫(kù));
    • ATen parallel backend: NATIVE;
    • Sleef(thirdparty下的三方庫(kù));
    • 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構(gòu)建的時(shí)候會(huì)使用python腳本(tools/codegen/gen.py)生成一些cpp源文件,這個(gè)python腳本對(duì)yaml、dataclasses模塊有依賴,因此,在開始編譯前,你需要安裝這些包:

    root@gemfield:~# pip3 install setuptools root@gemfield:~# pip3 install pyyaml root@gemfield:~# pip3 install dataclasses

    PyTorch官方預(yù)編譯動(dòng)態(tài)庫(kù)的編譯選項(xiàng)

    如果對(duì)官方編譯的庫(kù)所選用的編譯開關(guān)感興趣的話,可以使用如下的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版本靜態(tài)庫(kù)(MKL后端)

    在這個(gè)最小尺度的CPU版本里,Gemfield將會(huì)選擇MKL作為L(zhǎng)APACK的實(shí)現(xiàn)。此外,Gemfield將會(huì)首先禁用CUDA,這是自然而然的。其次Gemfield還要禁用caffe2(因?yàn)槟康氖蔷幾glibtorch),這會(huì)連帶著禁用caffe2的op。整體要禁用的模塊還有:

    • caffe2;
    • 可執(zhí)行文件;
    • python;
    • test;
    • numa;
    • 分布式(DISTRIBUTED);
    • ROCM;
    • GLOO;
    • MPI;
    • CUDA;

    1,安裝MKL

    既然選擇了MKL,第一步就是要安裝它。MKL使用的是ISSL授權(quán)(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-912

    2,使用CMake構(gòu)建

    命令如下:

    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

    然后使用如下的命令進(jìn)行編譯:

    cmake --build . --target install -- "-j8"

    編譯成功后,生成的靜態(tài)庫(kù)有(23個(gè),其中一個(gè)是鏈接文件):

    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編譯開關(guān):

    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

    生成的靜態(tài)庫(kù)有26個(gè),除了上面的非caffe2版本,還多出來了perfkernel模塊生成的:

    libCaffe2_perfkernels_avx.a libCaffe2_perfkernels_avx2.a libCaffe2_perfkernels_avx512.a

    這三個(gè)庫(kù)包含了如下的API,實(shí)現(xiàn)了一些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,但本文不討論——因?yàn)镚emfield編譯的靜態(tài)庫(kù)要滿足不同模型的推理。

    3,使用pytorch靜態(tài)庫(kù)(MKL后端版本)

    如何讓自己的程序鏈接該靜態(tài)庫(kù)呢?由于MKL依賴openmp,因此編譯的命令行參數(shù)要打開(-fopenmp )。而PyTorch的代碼又需要依賴以下的MKL靜態(tài)庫(kù):

    /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

    以及依賴系統(tǒng)上的這幾個(gè)共享庫(kù):

    /usr/lib/x86_64-linux-gnu/libpthread.so /usr/lib/x86_64-linux-gnu/libm.so /usr/lib/x86_64-linux-gnu/libdl.so

    因此你的程序需要鏈接這些庫(kù)(除了鏈接pytorch那二十幾個(gè)靜態(tài)庫(kù)外)才能完成編譯。感覺很復(fù)雜是吧?忘記這些吧,使用我們開源的libdeepvac庫(kù)吧。libdeepvac封裝了libtorch,提供更簡(jiǎn)化的C++中使用PyTorch模型的方法。

    編譯最小尺度的CPU版本靜態(tài)庫(kù)(Eigen后端)

    在這個(gè)最小尺度的CPU版本里,Gemfield將會(huì)選擇Eigen來作為L(zhǎng)APACK的實(shí)現(xiàn)。使用Eigen來作為L(zhǎng)APACK實(shí)現(xiàn)的話,需要打開INTERN_USE_EIGEN_BLAS??匆奍NTERN前綴了吧,這提示我們不應(yīng)該這樣來使用這個(gè)開關(guān)。并且由于在PyTorch中,Eigen是為mobile平臺(tái)而設(shè)計(jì)使用的,因此要想在x86_64 Linux使用,就需要改下pytorch倉(cāng)庫(kù)中的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進(jìn)行構(gòu)建

    命令如下(注意開啟了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

    然后使用如下的命令進(jìn)行編譯:

    cmake --build . --target install -- "-j8"

    編譯出來的靜態(tài)庫(kù)如下所示(24個(gè),注意多出來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.a

    3,使用pytorch靜態(tài)庫(kù)(Eigen后端版本)

    和MKL后端不同,你的程序需要從鏈接MKL轉(zhuǎn)而去鏈接libeigen_blas.a,更簡(jiǎn)單了。如果使用libdeepvac庫(kù)的話,這都是無感的。

    和MKL后端的靜態(tài)庫(kù)進(jìn)行了下粗略的性能比較,在6核intel處理器的系統(tǒng)上,對(duì)20個(gè)目標(biāo)進(jìn)行CNN+LSTM的計(jì)算下,MKL版本消耗了11秒,而Eigen版本消耗了20秒。所以還是推薦使用MKL。

    編譯最小尺度的CUDA版本靜態(tài)庫(kù)(無MAGMA版本)

    1,配置

    相關(guān)的配置如下:

    • 要編譯CUDA版本,必須啟用USE_CUDA;
    • 另外,回落到CPU的時(shí)候,我們依然需要有對(duì)應(yīng)的LAPACK實(shí)現(xiàn),這里還是選擇MKL,安裝方法見前文;
    • 還有一個(gè)地方需要注意:是否使用MAGMA。這里Gemfield先不使用。

    2,CUDA架構(gòu)

    同CPU版本相比,編譯CUDA版本的最大不同就是要指定CUDA架構(gòu)(開普勒、麥克斯韋、帕斯卡、圖靈、安培等)。要編譯特定CUDA架構(gòu)的目標(biāo),需要給NVCC編譯器傳遞特定架構(gòu)的號(hào)碼,如7.0。特定架構(gòu)的號(hào)碼有兩種情況:PTX和非PTX。比如7.0 和 7.0 PTX。

    非PTX版本是實(shí)際的二進(jìn)制文件,只能做到主版本號(hào)兼容。比如compute capability 3.0 的編譯產(chǎn)物只能運(yùn)行在compute-capability 3.x的架構(gòu)上(開普勒架構(gòu)),而不能運(yùn)行在compute-capability 5.x (麥克斯韋) 或者 6.x (帕斯卡) 設(shè)備上。

    而PTX版本編譯出來的是JIT的中間代碼,可以做到前向兼容——也就是舊設(shè)備的目標(biāo)可以運(yùn)行在新設(shè)備上。因?yàn)榫幾g的時(shí)候可以指定多個(gè)架構(gòu)號(hào)碼,因此一個(gè)技巧就是,總是在最高的版本號(hào)上加上PTX,以獲得前向兼容,比如:3.5;5.0;5.2;6.0;6.1;7.0;7.5;7.5+PTX。

    另外,在不兼容的CUDA設(shè)備上運(yùn)行你的程序會(huì)出現(xiàn)“no kernel image is available for execution on the device”錯(cuò)誤。編譯PyTorch的時(shí)候,這個(gè)CUDA架構(gòu)號(hào)碼來自三種方式:

    • 自動(dòng)檢測(cè)本地機(jī)器上的設(shè)備號(hào);
    • 檢測(cè)不到,則使用默認(rèn)的一組;
    • 用戶通過TORCH_CUDA_ARCH_LIST環(huán)境變量指定。TORCH_CUDA_ARCH_LIST環(huán)境變量,比如TORCH_CUDA_ARCH_LIST="3.5 5.2 6.0 6.1+PTX",決定了要編譯的pytorch支持哪些cuda架構(gòu)。支持的架構(gòu)越多,最后的庫(kù)越大;
    #cuda9 export TORCH_CUDA_ARCH_LIST="3.5;5.0;5.2;6.0;6.1;7.0;7.0+PTX"#cuda10 export TORCH_CUDA_ARCH_LIST="3.5;5.0;5.2;6.0;6.1;7.0;7.5;7.5+PTX"#cuda11 export TORCH_CUDA_ARCH_LIST="3.5;5.0;5.2;6.0;6.1;7.0;7.5;8.0;8.0+PTX"#cuda11.1 export TORCH_CUDA_ARCH_LIST="5.0;7.0;8.0;8.6;8.6+PTX"

    一些市面上常見顯卡的compute-capability號(hào)碼如下所示:

    3,使用CMake進(jìn)行構(gòu)建

    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構(gòu)建時(shí)還會(huì)檢測(cè):

    • -- 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;

    然后使用如下的命令進(jìn)行編譯:

    cmake --build . --target install -- "-j8"

    編譯出如下的靜態(tài)庫(kù)(26個(gè)):

    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個(gè)靜態(tài)庫(kù)。

    4,使用pytorch靜態(tài)庫(kù)(CUDA版本)

    和CPU版本類似,但是區(qū)別是還要鏈接NVIDIA的cuda運(yùn)行時(shí)的庫(kù)(這部分是動(dòng)態(tài)庫(kù))。此外,如果你的程序初始化的時(shí)候報(bào)錯(cuò):“PyTorch is not linked with support for cuda devices”,說明你沒有whole_archive c10_cuda.a靜態(tài)庫(kù)。

    如果你編譯自己程序的時(shí)候遇到了cannot find -lnvToolsExt、cannot find -lcudart這樣的錯(cuò)誤,你還需要設(shè)置下環(huán)境變量讓鏈接器能夠找到cuda運(yùn)行時(shí)的庫(kù):

    root@gemfield:~# export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/cuda-10.2/targets/x86_64-linux/lib/

    總之,你如果使用了libdeepvac封裝的話(需要打開USE_CUDA),就沒有這么多問題了。

    5,性能

    做了一個(gè)快速的不嚴(yán)謹(jǐn)?shù)耐评硇阅軠y(cè)試。使用了cuda版本后,還是之前的那個(gè)系統(tǒng),還是之前那個(gè)測(cè)試任務(wù)(對(duì)20個(gè)目標(biāo)進(jìn)行CNN+LSTM的計(jì)算下),CUDA版本消耗了不到一秒。

    最后

    在你使用pytorch靜態(tài)庫(kù)的時(shí)候,或多或少還會(huì)遇到一些問題。但是,何必自討苦吃呢,使用我們封裝了libtorch的libdeepvac庫(kù)吧:

    DeepVAC/libdeepvac?github.com

    總結(jié)

    以上是生活随笔為你收集整理的pytorch 矩阵相乘_编译PyTorch静态库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。