美文网首页
MindSpore Windows 编译系列(一):如何在Win

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

作者: iambowen | 来源:发表于2022-04-10 11:18 被阅读0次

    当前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是启动编译的批处理脚本,脚本中有两处变量会影响到编译的效率:

    • SET threads=8:设置并行编译的线程数,默认为8。如果你的处理器支持的线程数更高,可以修改为更大的数字,比如我的CPU是8核16线程,这个地方我就改成了16;
    • SET ENABLE_GITEE=ON:是否通过gitee下载三方库的压缩包,默认从github下载。如果网络访问外网环境不太好,可以选择修改为ON,加快下载速度;

    这些准备完成后,就可以在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的编译,首先得理清楚过程中都依赖了什么,编译了那些模块,功能和作用是什么,这也是下一步需要分析和完成的内容。

    相关文章

      网友评论

          本文标题:MindSpore Windows 编译系列(一):如何在Win

          本文链接:https://www.haomeiwen.com/subject/qcrvsrtx.html