MindSpore Windows 编译系列(一):如何在Win

2022-04-10  本文已影响0人  iambowen

当前MindSpore对于Windows平台的支持仍有欠缺,比如不支持GPU,编译工具链导致的无法编译debug版本而影响问题定位效率等。今年MindSpore将尝试通过社区如易用性sig协作的方式,共同把这些问题解决,为MindSpore的Windows用户提供更好的使用体验。

个人以前也没有Windows以及MindSpore框架开发的经验,在网络搜索关于MindSpore的资料时,找到的更多是关于如何使用MindSpore进行网络实现和训练、推理,没有从框架贡献者的角度介绍如何参与或者给MindSpore贡献代码的内容。所以,想借这个机会记录好Windows下这些问题解决的过程,既能联合社区的朋友们解决MindSpore在Windows下的问题,也能提升自己对于Windows下开发、对于MindSpore在架构和代码层面的理解,还可以为想给MindSpore贡献代码的同学提供一些参考。

在开始解决实际的问题前,我想第一步应该是参考MindSpore官网的安装指南来完成Windows下CPU版本的编译,本文就是记录下我编译安装的过程以及发现的问题。

Windows下编译MindSpore CPU版本

1. 安装依赖软件

MindSpore的CPU版本在编译时依赖软件及安装方式如下表:

软件 版本要求 用途 安装方法
Windows 10,64位 操作系统平台
python 3.9.0/3.7.5 Python语言解释器 3.9.0 下载地址,直接安装即可
mingw 7.3.0 编译工具链 下载地址,解压后将目录加入到Path环境变量下
git 2.29.0 版本管理工具 下载地址,下载直接安装即可
cmake >3.18.3 构建工具 下载地址,下载64位MSI版本直接安装即可
strawberry perl 5.28.1.2801 perl编译器 下载地址,解压后将Perl的bin目录加到Path环境变量中
wheel >0.32.0 Python打包工具 执行pip install wheel即可

官网的Windows编译安装指南中推荐使用ActivePerl,但其下载过程中还需要注册,体验并不好,所以我使用了strawberry perl,而且最好是zip包,因为MSI的安装会将额外的gcc编译工具链添加到Path中,影响编译中gcc编译器的选择;

对于以上需要安装的工具,exe以及msi格式的软件包都可以自动配置bin目录到Path环境变量中(有些需要在安装过程中指定,如cmake),而压缩包版本则需要在解压后,手动在Windows的环境变量Path中添加新的路径。如下图,如果strawberry-perl-5.28.2.1-64bit.zip被解压到D盘的根目录,可以在系统变量Path或者用户变量Path中增加D:\Strawberry\perl\bin的项目,同理,也需要增加mingw bin的路径,如图中的D:\mingw64\bin

perl.png

另一个需要配置的是pip的镜像源,可以考虑使用华为云Python镜像,在C:\Users\<UserName>\pip\pip.ini中添加如下内容即可:

[global]
index-url = https://repo.huaweicloud.com/repository/pypi/simple
trusted-host = repo.huaweicloud.com
timeout = 120

2. 下载MindSpore源码编译

首先通过git clone --depth=1 https://gitee.com/mindspore/mindspore.git -b r1.6 下载框架的源码,这里指定了1.6版本的tag,原因当前的master分支编译会出错……。

然后启动Windows的CMD,然后切换到代码仓库的目录,正式开始编译前可以设置下patch的环境变量MS_PATCH_PATH,以防止在三方库打patch时因为git安装路径的问题找不到patch命令,方式和第一部分中添加Path环境变量类似。首先在cmd中通过where git找到git的安装目录,如D:\Program Files\Git\cmd\git.exe,然后创建一个新的用户环境变量MS_PATCH_PATH,赋值为D:\Program Files\Git\usr\bin。最后在cmd 输入 refreshenv完成环境变量刷新。

MindSpore代码仓根目录下的build.bat是启动编译的批处理脚本,脚本中有两处变量会影响到编译的效率:

这些准备完成后,就可以在cmd中执行call build.bat开始编译,正常大约1小时左右就可以完成编译,生成mindspore的whl包。

3. 安装编译版本并检查

MindSpore的编译好的whl包路径在build\package\下,切换到该目录下,使用pip install mindspore-1.6.1-cp39-cp39-win_amd64.whl ,执行运行检查:

D:\Workspace\mindspore\build\package>python -c "import mindspore;mindspore.run_check()"
MindSpore version:  1.6.1
The result of multiplication calculation is correct, MindSpore has been installed successfully!

可以运行,表明编译成功。

发现的问题/改进点

如果一切顺利,整个的编译时间大概在一小时多一点,但实际上我花了大约1天的时间,原因是在过程中碰到了一些列的问题。

  1. 使用conda的Python环境,编译Protobuf失败。如果你的Python环境是通过conda去做管理的,在编译Protobuf三方库会遇到这样的错误:
-- 3.13.0.0
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Found ZLIB: C:/Users/lenovo/.conda/envs/py39/Library/lib/z.lib (found version "1.2.11")
-- Performing Test protobuf_HAVE_BUILTIN_ATOMICS
-- Performing Test protobuf_HAVE_BUILTIN_ATOMICS - Success
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Workspace/mindspore/build/mindspore/_deps/protobuf-src/_build
Scanning dependencies of target libprotobuf-lite
In file included from D:\Workspace\mindspore\build\mindspore\_deps\protobuf-src\src\google\protobuf\arena.cc:37:0:
C:/Users/lenovo/.conda/envs/py39/Library/include/google/protobuf/stubs/mutex.h: In constructor 'constexpr google::protobuf::internal::WrappedMutex::WrappedMutex()':
C:/Users/lenovo/.conda/envs/py39/Library/include/google/protobuf/stubs/mutex.h:124:29: error: temporary of non-literal type 'google::protobuf::internal::CallOnceInitializedMutex<std::mutex>' in a constant expression
   constexpr WrappedMutex() {}
                             ^
……                             

protobuf.cmake中用-Dprotobuf_WITH_ZLIB=OFF屏蔽zlib后可以完成编译,但具体影响的功能不祥。

mindspore_add_pkg(protobuf
        VER 3.13.0
        LIBS protobuf
        EXE protoc
        URL ${REQ_URL}
        MD5 ${MD5}
        CMAKE_PATH cmake/
        CMAKE_OPTION -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB=OFF
        PATCHES ${PROTOBUF_PATCH_ROOT}/CVE-2021-22570.patch)

通过上面的日志发现编译时用到了conda的zlib、protobuf头文件,并非框架下载zlib和protobuf,推测根源的问题在这里。检查系统环境变量,发现miniconda在安装时自动的在Path环境变量中添加了mingw的类库路径,而这个路径下包含了编译框架需要的zlib、protobuf的一些头文件,版本不一致导致了protobuf的编译错误。将下图中包含Library路径从Path变量中去掉后,在不修改protobuf.cmake的情况下也可以正常编译。

conda.png
  1. master分支编译完成安装后出现导入错误。具体的错误信息如下:
(py39) D:\Workspace\mindspore\build\package>python -c "import mindspore;mindspore.run_check()"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "D:\Workspace\mindspore\build\package\mindspore\__init__.py", line 29, in <module>
    from .rewrite import *
ModuleNotFoundError: No module named 'mindspore.rewrite'
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "D:\Workspace\mindspore\build\package\mindspore\__init__.py", line 29, in <module>
    from .rewrite import *
ModuleNotFoundError: No module named 'mindspore.rewrite'

屏蔽对应的代码行可以正常运行,但这个错误不应该出现,master上合入的代码应该保证基本的功能,这里的自动化测试环节没有能照顾到这个基础的健康检查。这也是为什么上面的编译使用了1.6版本的分支而非master的原因。

  1. 是否有必要引入perl这个依赖。我检查了MindSpore代码仓中对于perl的使用,结果发现Windows下只有protobuf的cmake有使用,
        if(WIN32)
            add_custom_command(
                    OUTPUT "${CMAKE_BINARY_DIR}/proto/${file_name}.pb.cc"
                    "${CMAKE_BINARY_DIR}/proto/${file_name}.pb.h"
                    "${CMAKE_BINARY_DIR}/proto/${file_name}_pb2.py"
                    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
                    ...
                    COMMAND perl -pi.bak -e "s/import (.+_pb2.*)/from . import \\1/"
                            "${CMAKE_BINARY_DIR}/proto/${file_name}_pb2.py"
                    ...
                    COMMENT "Running C++ protocol buffer compiler on ${file}" VERBATIM)

这里perl命令的作用是把所有*_pb2.py的python文件中的import xxx as xxx 替换为 from . import xxx as xxx。如果没有其它的库依赖perl,这里可以考虑用inline的python命令、cmd命令行工具或者sed(for windows)来替换,最优的情况下可以在安装和编译的过程中减少一个依赖,提升使用体验。

总结

本次的MindSpore CPU版本编译过程中发现了3个问题:conda管理的python环境编译、master编译后的执行错误以及编译依赖perl的问题,针对这几个问题,我在gitee的代码仓中创建了issue并添加kind/bugcomp/build-install标签,方便负责相应领域的开发人员进行分析和解决问题。

编译的过程中出现了大量的三方库以及模块的编译过程,要理解MindSpore的编译,首先得理清楚过程中都依赖了什么,编译了那些模块,功能和作用是什么,这也是下一步需要分析和完成的内容。

上一篇下一篇

猜你喜欢

热点阅读