MindSpore Windows 编译系列(一):如何在Windows下编译MindSpore CPU版本

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容