admin 管理员组

文章数量: 887018

目录

  • 0 前言
  • 1 Basic Configure
    • 1.1 Main Build environment
    • 1.2 Main Tools
    • 1.3 Configure
  • 2. Build Tensoflow (latest | 2.8.0rc0)
    • 2.1 建立小环境,安装必要的包
    • 2.2 下载Tensoflow源码
    • 2.3 配置configure
    • 2.4 开始编译
    • 2.5 编译完成
  • 3 Build Pytorch(latest | v1.10.2-rc1)
    • 3.1 建立小环境,安装必要的包
    • 3.2 下载pytorch源码
    • 3.3 下载安装magma、mkl、sccache
    • 3.4 开始编译
    • 3.5 编译完成
  • 4 如何同时存在tensorflow 和pytorch
  • 5 后记

非引流,奈何实在没有精力维护CSDN,而编译过程时常更新,关于TensorFlow的编译,可以移步维护更加频繁的 个人博文,而Pytorch编译依旧可以参考此篇。

0 前言

记录了如何在window平台,跟上cuda和cudnn的版本更新步伐,成功编译pytorch和tensorflow的过程。不要让平台、软件版本成为研究的阻碍和桎梏。

开头回答3个问题:

  • 为什么是windows而非linux:
  1. 必要性:本人只有一台非苹果主机,也没有笔记本电脑,必须同时用来工作、研究、学习和一般的生活琐事中的计算机需要,综合考虑下,选择Windows。
  2. 优点:Office、Adobe、Autodesk这类和操作系统太过相关的全家桶软件就可以随意使用,Matlab也很方便。目前纯Windows下的pytorch和tensorflow至少比WSL有更大的适配空间和参考内容。
  3. 缺点:纯Windows下cuda、cudnn、pytorch和tensorflow的编译与适配可以参考的内容不多,但其实并不困难。如果有使用和维护Linux服务器的同学,完全可以参考,编译器和环境变量部分的需要改动我会以这个颜色说明本文保证所有的Debug问题根源都非windows平台独有,换而言之,仅仅切换到Linux而维持其余软件版本号不变,bug是始终存在的,只是网上linux下的debug过程写的和提问的人比较多、看起来容易参考和解决罢了,本质上的问题一定不是平台问题,不要搞对立。
  • 为什么要跟上cuda和cudnn的版本更新步伐:新硬件决定了需要新驱动,而新驱动不适配旧cuda和cudnn。编译cuda-toolkit这种虚无缥缈的事情还是不要考虑了。
  • 熟练编译的作用:随着研究的深入,需要用到自定义算子,熟练编译是我研究的必经之路,于此同时,也等于脱离了框架的桎梏,真正的让他们为我所用。

本文只讨论Relative latest environment,指的是不一定最新,但不算老旧的环境。
目标:

  • 稳定可使用:工具尽可能选择非pre或非rc版本,不编译nightly版
  • 可溯源、易复现:Tensorflow和Pytorch最新只能为确定tags的rc版,不编译不断变化的master分支
  • 获取便捷:不需为了版本兼容而在各大仓库翻看历史版本,尤其是cuda和cudnn
  • 不造无意义的轮子:允许适量debug以加深对框架底层的理解,但不要特别繁琐,不然就陷进去无法自拔,走了开发和维护人员的路,这条路既没有他们专业,也和自己使用工具辅助研究的目的相悖。

1 Basic Configure

必要的环境与工具指明

1.1 Main Build environment

Windows 11
Miniconda  python(latest | 3.9) 3.10并不支持,需要大改所以摒弃
cuda(latet | 11.5)
cudnn(latest | 8.3)

1.2 Main Tools

CMD
PowerShell(latest | 7.2.1)
MSYS2
VS2022 MSVC(v142 | v143)
Bazel (latest | 4.2.2)
Cmake(Latest | 3.22.1)

1.3 Configure

若为window平台必须,而Linux不必要的操作将标注*号

  • Windows 11(略)

  • 验证CMD*
    系统自带的,不会有人自己卸载了吧

  • 下载安装PowerShell7.2.1*

  • 下载安装VS2022*
    建议默认位置安装 省下很多麻烦
    安装msvc v142(vs2022) v142(vs2019) 工具集

  • 下载安装miniconda

    • 安装时全部默认,建议不要勾选非推荐选项,避免环境变量污染。

    • conda换源 比如清华源 遵循清华源的官方教程很方便。

    • 配置conda与shell适配:
      打开Anaconda Prompt (miniconda3) 或者Anaconda Powershell Prompt (miniconda3)一次
      运行conda init 命令 ------可自动检测和初始化所有shell(CMD、系统自带powershell5和安装的powershell7.2.1)
      我选择删除注册表中CMD的启动附加和"~\Documents\WindowsPowerShell\profile.ps1”
      只保留“~\Documents\PowerShell\profile.ps1”
      整个编译过程profile.ps1都将呈现如下形式,可以 适当参考

      #profile.ps1
      #region conda initialize
      # !! Contents within this block are managed by 'conda init' !!
      (& "C:\Users\zhaop\miniconda3\Scripts\conda.exe" "shell.powershell" "hook") | Out-String | Invoke-Expression
      #endregion
      $env:Path="$env:Path;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.5\extras\CUPTI\lib64"
      $env:Path="$env:Path;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.5\bin"
      $env:Path="$env:Path;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.5\libnvvp"
      $env:Path="$env:Path;D:\Tools\zlib\dll_x64"
      $env:Path="$env:Path;C:\msys64\usr\bin"
      $env:Path="$env:Path;D:\Tools\bazel"
      #$env:HTTP_PROXY="http://127.0.0.1:7890"
      #$env:HTTPS_PROXY="https://127.0.0.1:7890"
      $env:Path="$env:Path;D:\Tools\CMake\bin"
      $env:BAZEL_VC="C:\Program Files\Microsoft Visual Studio\2022\Community\VC"
      $env:BAZEL_VC_FULL_VERSION="14.29.30133"
      #$env:BAZEL_VC_FULL_VERSION="14.30.30705"
      

      保留的prefile文件中就是PowerShell7.2.1的启动附加命令,其中指定了conda位置,我们可以在这里附加我们编译时需要环境变量,这和Linux通过修改profile或bashrc以更新环境变量是相通的

  • 下载安装 cuda11.5.1
    务必遵循最新的安装指导文档cuda-installation-guide
    安装cuda时建议全选,编译tensorflow不需要NVTX,但是编译pytorch时其官方文档说需要
    安装完成后,会新增若干环境变量以及若干path中的路径,不必担忧这部分内容,照常把path中cuda相关路径在如上profile.ps1中进行添加

  • 下载安装 cudnn8.3.1
    务必遵循最新的安装指导文档 cudnn-install-guide
    切记,cudnn8.3 需要指定zlib的zlibwapi.dll到path中,可以参考profile.ps1

  • 下载安装 cmake3.22.1
    安装完成后 将其添加到系统path中,可以参考profile.ps1

  • 下载安装 bazel4.2.2
    下载完成后不需要安装,只需要添加到系统path中以便于shell可以运行bazel,可以更名为bazel.exe存储与任意位置,比如参考profile.ps1的“D:\Tools\bazel”文件夹下保存bazel.exe
    设置BAZEL_VC和BAZEL_VC_FULL_VERSION环境变量,需要和msvc v142或者v143等对应,可参考profile.ps1,
    一般的,为了稳定BAZEL_VC_FULL_VERSION应当设置msvc v142版本 即(14.29.30133),这是vs2019的对应版本,但我们没有必要装两个VS,只需要在VS里面装两个工具及即可。

    可以给bazel挂上代理,环境变量中设置HTTP_PROXY 和HTTPS_PROXY即可,可参考profile.ps1
    但会和conda冲突,需要conda进行包管理时记得取消这两个环境变量以免被conda拾取

  • 下载安装MSYS2 *
    我们只是为了获得包管理器pacman
    安装完成后可以依据官方文档更新,裸连、翻墙或者是先换源如清华源皆可
    然后其将bin文件夹添加至系统path中,如C:\msys64\usr\bin,可以参考profile.ps1
    以pacman安装zip unzip patch diffutils git
    如:

    pacman -S zip unzip patch diffutils git
    

    十分建议给git挂上代理,如假设127.0.0.1:7890是代理的端口

    git config --global http.proxy http://127.0.0.1:7890 # 设置http proxy  
    git config --global https.proxy https://127.0.0.1:7890 # 设置https proxy
    #git config --global --unset http.proxy # 取消http proxy
    #git config --global --unset https.proxy # 取消http proxy
    

2. Build Tensoflow (latest | 2.8.0rc0)

在conda小环境中完成编译

2.1 建立小环境,安装必要的包

conda create -n py3.9 python=3.9
conda activate py3.9
pip install six numpy wheel keras_applications==1.0.6 --no-deps keras_preprocessing==1.0.5 --no-deps

2.2 下载Tensoflow源码

git clone -b v2.8.0-rc0 https://github.com/tensorflow/tensorflow.git
cd tensorflow

2.3 配置configure

python ./configure.py

弹出交互信息

  • python路径 检查默认路径是否是conda的 py3.9下的路径 是就回车
  • python library 路径 检查默认路径是否是conda的py3.9下的路径 是就回车
  • ROCm support 默认为N 直接回车 (应该都是N卡把,A卡我没试过)
  • CUDA support 输入Y回车
  • supports compute capabilities:输入对应的显卡算力,如8.6 然后回车
    如果想要面对多个平台,比如希望编译后可以同时支持6.1算力和8.6算力的设备,这里就输入 6.1,8.6 然后回车。支持算力的设备越多,编译后的文件越大,我们平时从Pipy下载的tensorflow的wheel支持市面上所有算力,所以会很大,我们单独针对某个算力的编译,文件会轻量很多
  • specify optimization flags 默认即可 啥都不输入然后回车,如果CPU支持AVX2(AVX256) 或 AVX512,那么输入对应的 /arch:AVX2 或者/arch:AVX3即可
  • C++ compilation 默认Y,回车
  • configure ./WORKSPACE for Android 默认N,回车

2.4 开始编译

"–config=cuda"参数是没有必要的,因为上面已经设置过cuda了, “–jobs 16"可以限制编译时的线程数 类似于"make -j16”,但没啥实际作用,即使CPU有10个核心, "–jobs 8"还是会100%占用,因为CPU的线程调度由操作系统和bios设置最终决定,bazel仅仅是一个程序。

bazel build --jobs 16 --config=opt --define=no_tensorflow_py_deps=true //tensorflow/tools/pip_package:build_pip_package

DEBUG

  • 如果报错

    [WinError 1314] 客户端没有所需的特权
    

    找到bazel的用户install目录, 比如我的目录为“C:/Users/zhaop/_bazel_zhaop/install”删除该目录下所有内容,以管理员权限运行终端,重新进到tensorflow下载目录,从配置configure开始重新进行即可,别忘了切换conda环境。如果上述目录无法删除,打开资源监视器搜索该目录句柄结束相应进程后再删除。

  • 如果报错

    Traceback (most recent call last): 
    File "D:/tools/tensorflow/tensorflow/third_party/gpus/cuda_configure.bzl 
    ...
    	return find_msvc_tool(repository_ctx, vc_path, "cl.exe").replace("\\", "/")
    Error: 'NoneType' value has no field or method 'replace'
    

    这很合理,是因为bazel4.x先于VS2022正式版出来,所以不支持,具体的,tensorflow/third_party/gpus/cuda_configure.bzl文件中有

    load(
        "@bazel_tools//tools/cpp:windows_cc_configure.bzl",
        "find_msvc_tool",
        "find_vc_path",
        "setup_vc_env_vars",
    )
    

    导入了“C:/Users/zhaop/_bazel_zhaop/install”文件夹下某个地方的windows_cc_configure.bzl文件中的的find_msvc_tool,find_vc_path,setup_vc_env_vars函数,他们依赖于一个很蠢的私有函数_is_vs_2017_or_2019()

    	def _is_vs_2017_or_2019(vc_path):
    	    """Check if the installed VS version is Visual Studio 2017."""
    	    # In VS 2017 and 2019, the location of VC is like:
    	    # C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\
    	    # In VS 2015 or older version, it is like:
    	    # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
    	    return vc_path.find("2017") != -1 or vc_path.find("2019") != -1
    

    导致返回的不带有2019的VC路径为空而报错。

    • 方法1:修改windows_cc_configure.bzl中的该函数,如将返回值改为
      return vc_path.find("2017") != -1 or vc_path.find("2019") != -1 or vc_path.find("2022") != -1
      
      但是windows_cc_configure.bzl是bazel的基础性文件,bazel不允许用户对其修改,即便改了也需要删除重新下载,所以摒弃该方法。
    • 方法2:patch的思想
      复制windows_cc_configure.bzl中find_msvc_tool,find_vc_path,setup_vc_env_vars函数源码以及他们自身依赖的函数源码,然后到tensorflow源码的cuda_configure.bzl中粘贴,即“patch prefix”的思想,重写了这些函数,克服方法1中无法修改的问题,再按照方法1修改复制过来的_is_vs_2017_or_2019()函数,从配置configure开始重新进行即可。
      缺点是工作量很大,并非仅cuda_configure.bzl文件调用了windows_cc_configure.bzl,大致需要修改tensorflow源码的三处,还需要声明两个不同的execute函数,权当娱乐自己的方法,长期使用不可取
    • 方法3:patch2
      为"C:\Program Files\Microsoft Visual Studio\2022"设置一个软链接“C:\Program Files\Microsoft Visual Studio\2019”
      cd C:\Program Files\Microsoft Visual Studio\
      New-Item -Path ./2019 -ItemType SymbolicLink -Value ./2022
      
      修改环境变量BAZEL_VC=“C:\Program Files\Microsoft Visual Studio\2019\Community\VC”
      配置configure开始重新进行即可。
    • 方法4:下载新版bazel6.0.0pre替换原先的bazel
      配置configure开始重新进行即可
      会报错提示bazel版本过高"Please downgrade your bazel installation to version 4.99.0 or lower to build TensorFlow!"
      不要慌,毕竟只有新版本才可以支持VS2022
      打开 “./configure.py” 将
      _TF_MAX_BAZEL_VERSION = '4.99.0'
      
      改为
      _TF_MAX_BAZEL_VERSION = '9.99.0'
      
      配置configure开始重新进行即可。

    强烈推荐方法3,软链接的方法Linux平台也可行

  • 如果报错

    tensorflow\lite\python\analyzer_wrapper\model_analyzer[197]
    什么什么C2001 常量中有换行符
    

    老bug了,官方一直没人在意这个bug,每次rc版本更新都出现,找到“tensorflow\lite\python\analyzer_wrapper\model_analyzer”把197行字符串中的中文单引号换成英文单引号就好啦。

2.5 编译完成

生成wheel在C:/tmp/tensorflow_pkg下

bazel-bin\tensorflow\tools\pip_package\build_pip_package C:/tmp/tensorflow_pkg

需要一段不短的时间等待打包,最终得到whl即可用pip安装。install过程会进行版本控制,下载必要的其余的库包,比如numpy等。此时的numpy可能会被pip自动改装为tensorflow源码中指定的版本,没有关系,安装完成后再执行

pip install -U numpy

让numpy回到编译时的默认版本即可。原则是尽量默认,少改base。如果出现tensorflow源码中的numpy等版本冲突,是tensorflow的兼容性问题,大可停止编译,或者切换python版本,千万没必要做当前python版本下的numpy降级,会让编译陷入泥潭,失去意义。

3 Build Pytorch(latest | v1.10.2-rc1)

在conda小环境中完成编译

3.1 建立小环境,安装必要的包

conda create -n py3.9 python=3.9
conda activate py3.9
conda install astunparse numpy ninja pyyaml mkl mkl-include setuptools cffi typing_extensions future six requests dataclasses
conda install -c conda-forge libuv=1.39

以上命令严格遵循了Pytorch官方的编译教程,除了没有安装cmake没有任何魔改,不用担心编译出来的版本和官方编译好的版本有功能和效率上的区别。如果不小心用conda又安装了一遍cmake,需要单独卸载cmake以免和之前添加到系统path的cmake优先级冲突,但是保留其余一部分依赖,所以使用"–force"

conda remove -n py3.9 cmake --force

3.2 下载pytorch源码

下载后同步submodule
一般的,git不挂代理是无法完成submodule同步的

git clone -b v1.10.2-rc1 https://github.com/pytorch/pytorch.git
cd pytorch
git submodule sync
git submodule update --init --recursive --jobs 0

3.3 下载安装magma、mkl、sccache

cd ./.jenkins\pytorch\win-test-helpers\installation-helpers

首先设置一些零时的前提环境变量,用installation-helpers下的若干脚本帮我们下载对应的文件即可

$env:USE_CUDA="1"
$env:CUDA_VERSION="11.5"
$env:BUILD_TYPE="release"
  • magma
    ./install_magma.bat
    
    忽略其余脚本报错,得到磁盘的根目录下的magma_2.5.4_cuda115_release.7z,解压到一个位置,比如 D:\Tools\magma以获得include和lib
  • mkl
    ./install_mkl.bat
    
    忽略其余脚本报错,得到磁盘的根目录下的 mkl_2020.2.254.7z,解压到一个位置,比如 D:\Tools\mkl以获得include和lib
  • sccache
    ./install_sccache.bat
    
    忽略其余脚本报错,得到磁盘的根目录/bin下的sccache.exe和sccache-cl.exe,可以建立D:\Tools\sccache目录将bin移动到其中

3.4 开始编译

重新定位到pytorch 源码的根目录 需要自行指定。

cd ~/pytorch  # ~ 目录是自行指定的,依据自身的实际情况

建立一个build_init.bat脚本,脚本名字随意,我喜欢命名为“build_init.bat”,并以CMD而非powershell可接受的语法写入如下内容

:: Set the environment variables after you have downloaded and upzipped the mkl package,
:: else CMake would throw error as `Could NOT find OpenMP`.

set CMAKE_INCLUDE_PATH=D:\Tools\mkl\include;D:\Tools\magma\include
set LIB=D:\Tools\mkl\lib;D:\Tools\magma\lib
set path=%path%;D:\Tools\sccache\bin

:: Read the content in the previous section carefully before you proceed.
:: [Optional] If you want to override the underlying toolset used by Ninja and Visual Studio with CUDA, please run the following script block.
:: "Visual Studio 2019 Developer Command Prompt" will be run automatically.
:: Make sure you have CMake >= 3.12 before you do this when you use the Visual Studio generator.
set CMAKE_GENERATOR_TOOLSET_VERSION=14.29
set VCToolsVersion=14.29.30133

set DISTUTILS_USE_SDK=1
set USE_CUDA=1
set NVCC_GENCODE=-gencode=arch=compute_86,code=sm_86
set TORCH_CUDA_ARCH_LIST=8.6

:: [Optional] If you want to override the CUDA host compiler
set CUDAHOSTCXX=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64\cl.exe

"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 -vcvars_ver=%CMAKE_GENERATOR_TOOLSET_VERSION%

如上的脚本用于编译开始前的环境变量设置。指定了magma、mkl、sccache的位置,编译器版本,使用cuda,指定算力,复写了CUDAHOSTCXX,因为cuda11.5不支持mvsc 高于v142的编译器,利用vcvarsall.bat进行一些不需要我们关系的编译器指定操作,必须放在最后一行,不然会导致其后的脚本失效。
目前pytorch明面上虽然写着支持纯msvc编译,但还是依赖于ninja,强行脱离ninja而仅使用cmake和msvc时需要改动2~3处源码,虽然是一些不值一提的脚本bug,没必要,用ninja又快又好

conda activate py3.9 #切换到目标环境
cmd # 启动CMD pytorch在cmake编译时不支持powershell
build_init.bat
python setup.py develop bdist_wheel #同时生成wheel 

DEBUG
不出意外的话,就会出现如下的错误

 error: namespace "cub" has no member "Debug" 

依据Refactor cub namespace handling #66219进行修改,其实master分支已经不需要修改了,但pytorch1.10.2-rc1还是需要修改的。
修改后重新编译即可。

python setup.py clean
python setup.py develop bdist_wheel#同时生成wheel 

3.5 编译完成

编译完成后,由于“–traget install”存在于源码中的命令,所以每次build都会进行一次安装,同时,在“D:\Tools\pytorch\pytorch\dist”
下得到“torch-1.10.0a0+git71f889c-cp39-cp39-win_amd64.whl”,
可以先安装torchvision等相应库包,因为torchvision会自动安装cpu版的pytorch,然后再安装“torch-1.10.0a0+git71f889c-cp39-cp39-win_amd64.whl”覆盖cpu版本的pytorch。即

exit # 退出CMD
pip install torchvision 
pip install .\dist\torch-1.10.0a0+git71f889c-cp39-cp39-win_amd64.whl#会覆盖所有之前的安装

忽略pip弹出的版本兼容警告。至此,pytorch编译安装完成。

4 如何同时存在tensorflow 和pytorch

细心的同学已经发现了,上述tensorflow 和pytorch编译过程势必产生矛盾,因为严格遵循了pytorch的官方编译教程,编译pytorch时安装的numpy由conda管理,且版本不是最新,如果在同一环境下,先编译tensorflow 安装,然后编译pytorch安装,会
导致存在两个不同版本的numpy,进而出现一系列矛盾和bug,因此若要tensorflow 和pytorch共存,最好还是进行如下操作。
PS:千万不要在pytorch源码目录下import torch测试

建议建立新环境,因为pytorch的编译会破坏numpy环境,影响tensorflow

  1. 安装编译好的tensorflow wheel
  2. 升级numpy确保tensorflow 可用
  3. 安装pytorch必须的前提库(去掉编译时使用的cmake ninja 以及已经有的numpy six setuptools等)
  4. 安装pytorch wheel

可参考如下操作

conda create -n py3.9 python=3.9 #假设所有旧的环境已经删除
conda activate py3.9
pip install C:\tmp\tensorflow_pkg\tensorflow-2.8.0rc0-cp39-cp39-win_amd64.whl
pip install -U numpy
pip install torchvision torchaudio  
conda install astunparse pyyaml mkl mkl-include cffi typing_extensions future requests dataclasses
conda install -c conda-forge libuv=1.39 
pip install D:\Tools\pytorch\pytorch\dist\torch-1.10.0a0+git71f889c-cp39-cp39-win_amd64.whl

随便测试一下

python
import tensorflow as tf
a = (tf.Variable(0.0)+1)*128
a
import torch
x = torch.rand(5, 3)
x
torch.cuda.is_available()

5 后记

本文是我科研和学习间隙的尝试。生活、学业和研究工作遇到困难瓶颈,一切都是现在和将来的研究的需要。学无止境。如果不了解工具,就无法真正熟练使用工具。可能会持续更新。不想被操作系统、框架、平台、版本限制、唯一的办法就是深入地理解编译过程,后续会加入自定义算子的编译与使用流程。

从做科学研究的视角看去,操作系统、cuda、cudnn、pytorch、tensorflow,都只是做研究的工具,学习使用pytorch或者tensorflow框架的目的,是希望借助框架便捷的nn计算库、自动微分、数据管道和一些通用的辅助分析工具,以及python灵活的特性、快速得构建科学实验的实验方法。但本质上,还是科学研究的范畴,不存在学会了基本方法就可以做出好研究的必然性。科研的本质过程并未改变,只是计算机软硬件技术的革新导致的实验方法与环境的频繁改变,会干扰我们的研究思路。熟练编译,就可以从容不迫得应对,从而将关注点再次拉回科学研究的层面。还是那句话:不要让平台、软件成为研究的阻碍和桎梏。

本文标签: 正确地 最新 Windows pytorch TensorFlow