在 Windows 上使用 Python 绑定和 CUDA、TBB 和 MPI 构建 VTK

Build VTK with Python Bindings and CUDA, TBB, & MPI on Windows

问题

我无法在支持 CUDAMPITBBWindows 上将 VTK 加载到 python。使用默认 PyPI 分发(数小时或更长时间)进行生产时,体绘制速度慢得不合理,我需要利用我的硬件来加快计算速度。

我已经使用 CMakeVisual StudioPython 3.8.10-x64 成功构建了 VTK 9.3.0 并且有 binlibinclude,和 share 文件夹,并将它们添加到 PATH,但 Python 没有看到 vtk

Python 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import vtk
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'vtk'
>>>

我试图将生成的 Lib/site-packagesbinlibinclude 文件夹放在 C:\Program Files\Python38 中的适当位置,但我仍然得到DLL 加载错误:

> py -3.8
Python 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import vtk
Traceback (most recent call last):
  File "C:\Program Files\Python38\lib\site-packages\vtkmodules\__init__.py", line 13, in <module>
    from . import vtkCommonCore
ImportError: DLL load failed while importing vtkCommonCore: The specified module could not be found.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files\Python38\lib\site-packages\vtk.py", line 30, in <module>
    all_m = importlib.import_module('vtkmodules.all')
  File "C:\Program Files\Python38\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Program Files\Python38\lib\site-packages\vtkmodules\__init__.py", line 15, in <module>
    import _vtkmodules_static
ModuleNotFoundError: No module named '_vtkmodules_static'
>>>

设置


OS: Windows 10 Enterprise, x64-bit, Build 1909
CPU: 2x Intel(R) Xeon(R) Gold 6248R
Disk: 2TB NVMe M.2 SSD
RAM: 192 GB DDR4
Compute GPUs: 2x NVIDIA Quadro RTX8000 in TCC mode with NVLink
Display GPU: 1x NVIDIA Quadro RTX4000
Visual Studio: Visual Studio 16 2019 Community
Windows SDK: 10.0.19041.0, targeting 10.0.18363
Python: 3.8.10 x64-bit
CMake: 3.21.1 (I use CMake-GUI)
vcpkg: 2021-08-12
VTK Source: vtk-9.0.3-cp38-cp38-win_amd64 (download from VTK website; not GitHub master)
VTKPythonPackage: GitHub Link (...not sure if I need this...)
CUDA Toolkit: 11.4
TBB: 2021.3.0 (via Intel(R) oneAPI Base Toolkit)
MPI: 2021.3.0 (via Intel(R) oneAPI HPC Toolkit)


NOTE: If desired, Embree, OSPRay, and OpenVKL are available in the Intel(R) oneAPI Rendering Toolkit

准备


注意: 很多的程序下载、安装和配置,它们对于正确构建很重要。为了将此 post 缩短为 MRE(最小可重现示例),请直接转到 Steps to Reproduce 部分。

注意: 设置环境变量时,可能会报PATH长度大于2047的错误不允许。要克服这个障碍,最简单的方法是直接在 Windows 注册表中编辑路径。以管理员身份打开 regedit,导航至

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

并在那里设置 Path 变量。

提示: 要编辑 PATH,我从注册表复制并粘贴到 Word 中,然后 select 编辑 ; 并通过 selecting Ctrl+H; 替换为段落结尾 ^p,然后使用 Replace 工具,如下所示:

完成后,我只需将 ^p 替换为 ; 即可撤消更改。这对我来说比使用正则表达式要简单得多。


1。安装 Visual Studio

  1. 下载Visual Studio Installer

  2. 运行安装程序,选择Visual Studio Community 2019,selectDesktop development with C++。确保以下 selected in Individual Components

注意:(对 Windows 10Visual Studio 2019 的我来说,这些是 v142 )

  1. 确保相应的 binlibinclude 文件夹的路径在 System Environment VariablesPATH 中。这些可以是:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include

and/or

C:\Program Files (x86)\Microsoft Visual Studio19\Community\VC\Tools\MSVC.29.30133\bin\Hostx64\x64\
C:\Program Files (x86)\Microsoft Visual Studio19\Community\VC\Tools\MSVC.29.30133\lib\x64\
C:\Program Files (x86)\Microsoft Visual Studio19\Community\VC\Tools\MSVC.29.30133\include

注意:(我至少推荐后者。)

  1. 确保安装程序已设置以下附加 System Environment Variables
VS140COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\
VS160COMCOMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio19\Community\Common7\Tools\
VS2019INSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio19\Community
VSSDK140INSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VSSDK\

注意: 即使安装程序将这些下载到 Program Files (x86),它们实际上是x64-bit 程序(我知道...Windows 很奇怪...)

2。安装 CUDA

  1. 下载并运行cuda_11.4.1_471.41_win10.exe(link)

提示: 本地安装程序的下载时间会更长,但您的安装会 运行快点。我建议无论如何都要保存安装程序,以防你的 CUDA 工具包损坏或你需要在另一台机器上安装。

  1. 确保将以下内容添加到 System Environment Variables
  2. 中的 PATH
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\bin
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\libnvvp

旁白: 必须使用版本 11.4 VTK 9。但是,顺便说一句,在 CMake 中使用 10.2 时,如果 CMake 找不到 CUDA,这可能是因为 CUDA Toolkit 10.2 安装程序出于某种原因没有将 Visual Studio MSBuild Extensions 复制到您的 Visual Studio 文件夹。将文件复制到

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\extras\visual_studio_integration\MSBuildExtensions\

C:\Program Files (x86)\Microsoft Visual Studio19\Community\Common7\IDE\VC\VCTargets\BuildCustomizations

注意: 如果你想 运行 你的 GPU 处于 TCC 模式(警告: 这将禁用图形输出),and/or 如果您有两个通过 NVLink 连接的 GPU 并且想要激活 NVLink,运行 在命令提示符中输入以下命令:

> nvidia-smi -i 0 -dm 1
> nvidia-smi -i 1 -dm 1

假设您有两个 ID 为 0 和 1 的 GPU,您希望在 TCC 模式下 运行。 (要检查,只需 运行 nvidia-smi 并查看您要使用 -dm 开关在 TCC 模式下激活哪些 GPU)。 PugetSystems Instructions 在 CUDA 11 中发生了变化。NVIDIA 的较新驱动程序随 NVIDIA 控制面板一起提供,在 3D Settings 下不再有 Configure SLI, Surround, PhysX,特别是在使用 Quadro 卡而不是 GeForce 时卡片。相反,一旦设置了 TCC 模式,NVLink 就会被激活,这会禁用图形输出。他们提供的程序仅适用于 CUDA 10,因此即使启用了 CUDA 11,您也会遇到错误。

注意: 如果出现错误 "Intel Graphics Driver for Windows not found",请忽略它。您只需要 CPU.

的驱动程序

注意: 不要添加超过 /lib//libnvvp/文件夹路径。如果这样做,CMake 可能无法找到 CUDA。如果您必须添加其他文件夹(例如 CUPTI),我建议 lib/libnvvp/ 文件夹出现在 PATH FIRST

3。安装 CMake

  1. 下载并安装 CMake(...很简单)

4。安装 vcpkg

  1. 下载并配置 vcpkg:
cd C:\
git clone https://github.com/microsoft/vcpkg
cd vcpkg
.\bootstrap-vcpkg.bat
vcpkg integrate install
  1. System Environment Variables中的默认三元组设置为x64-windows:
VCPKG_DEFAULT_TRIPLET=x64-windows
  1. 使用 vcpkg install 安装端口。在 CMake 中按 Configure,每次找不到您要安装的依赖项时,使用 vcpkg search 搜索依赖项并使用 vcpkg install 安装它(要删除包,请使用 vcpkg remove)._

注意: 请注意 这取决于您安装的内容,这些依赖项需要 space 的 很多 并且需要 很长的时间 下载。

5。安装 Intel oneAPI Toolkits

注意: 这些包括 TBBMPIOSPRay,以及您需要的 Intel Fortran 编译器 ifort.exe

  1. 英特尔(R) oneAPI 基础工具包
  2. 英特尔(R) oneAPI HPC 工具包
  3. 英特尔(R) oneAPI 渲染工具包(用于 Embree、OSPRay 和 OpenVKL,可选

并将相应的libbininclude文件夹添加到PATH

6.安装 Intel SPMD Compiler

  1. Intel(R) Implicit SPMD Program Compiler

7。安装程序的附加依赖项

注意: 您可能不需要或不想需要这些。为了完整起见,我在这里添加它们。如果 CMake 抱怨找不到这些,我建议安装它们。

  1. Nullsoft Scriptable Install System
  2. WiX Toolset
  3. MySQL Community (GPL) Installer for Windows
  4. MySQL ODBC Connector
  5. Strawberry Perl

8。在 Windows

上不成功的依赖项

注意: 我已经尝试为这些安装二进制文件并将它们添加到 PATH,但是他们似乎在 Windows..

上不起作用

注意: 对于其中的每一个,您还可以尝试下载相应的 python 3.8 zip源文件(在 GitHub, under Releases, and on conda forge, under Files) to a folder on C:` 上,然后添加子文件夹 binlibinclude(和 share 如果可用)到 PATH System Environment Variable.

  1. OpenTurns 1.17
  2. GDAL 3.3.1

重现步骤

  1. 我先设置我的PATHVTK 将生成 binincludelibshare 文件夹,因此我确保它们位于 PATH 的前面。这是我的(提示:参考regedit中的设置PATH以避免Windows上面准备部分的 PATH 长度大于 2047 个字符的错误)

  2. 以管理员身份打开 x64 Native Tools Command Prompt for VS 2019 终端并 运行

> cmake-gui

这确保 vcvarsall.bat 是 运行 并且它设置的相应环境变量被传递给 CMake-GUI.

  1. 将 Source 文件夹设置为 C:\VTK\src,将 Build 文件夹设置为 C:\VTK

更新:2021 年 8 月 26 日(续...)

注意:不是答案。

几乎做完全相同的事情,但在 vtk.py 中,加上包括所有其他系统依赖项,使用 os.add_dll_directory() 不起作用:

"""This is the vtk module."""

import sys

if sys.version_info < (3, 5):
    # imp is deprecated in 3.4
    import imp
    import importlib

    # import vtkmodules package.
    vtkmodules_m = importlib.import_module("vtkmodules")

    # import vtkmodules.all
    all_m = importlib.import_module("vtkmodules.all")

    # create a clone of the `vtkmodules.all` module.
    vtk_m = imp.new_module(__name__)
    for key in dir(all_m):
        if not hasattr(vtk_m, key):
            setattr(vtk_m, key, getattr(all_m, key))

    # make the clone of `vtkmodules.all` act as a package at the same location
    # as vtkmodules. This ensures that importing modules from within the vtkmodules package
    # continues to work.
    vtk_m.__path__ = vtkmodules_m.__path__
    # replace old `vtk` module with this new package.
    sys.modules[__name__] = vtk_m

else:
    if sys.version_info >= (3, 8):
        import os

        if os.name == "nt":
            WIN_DLLS = set([r"C:\WINDOWS\System32\downlevel"])

            PY_ROOT = sys.exec_prefix
            PY_DLLS = set(
                [
                    os.path.join(PY_ROOT, "DLLs"),
                ]
            )

            try:
                VTK_DIR = os.environ["VTK_DIR"]
            except KeyError:
                VTK_DIR = None

            VTK_DLLS = set([])
            if VTK_DIR is not None:
                # Assumes default folder "bin" used in CMake configuration
                for root, dirs, files in os.walk(os.path.join(VTK_DIR, "bin")):
                    for file_ in files:
                        if file_.lower().endswith(".dll") or file_.lower().endswith(
                            ".pyd"
                        ):
                            if root not in VTK_DLLS:
                                VTK_DLLS.add(root)
                            break

            try:
                VULKAN_PATH = os.environ["VK_SDK_PATH"]
            except KeyError:
                VULKAN_PATH = None

            VULKAN_DLLS = set([])
            if VULKAN_PATH is not None:
                for root, dirs, files in os.walk(VULKAN_PATH):
                    for file_ in files:
                        if file_.lower().endswith(".dll"):
                            if root not in VULKAN_DLLS:
                                VULKAN_DLLS.add(root)
                            break

            try:
                CUDA_PATH = os.environ["CUDA_PATH"]
            except KeyError:
                CUDA_PATH = None

            CUDA_DLLS = set([])
            if CUDA_PATH is not None:
                for root, dirs, files in os.walk(CUDA_PATH):
                    for file_ in files:
                        if file_.lower().endswith(".dll"):
                            if root not in CUDA_DLLS:
                                CUDA_DLLS.add(root)
                            break

            try:
                ONEAPI_ROOT = os.environ["ONEAPI_ROOT"]
            except KeyError:
                ONEAPI_ROOT = None

            ONEAPI_DLLS = set([])
            if ONEAPI_ROOT is not None:
                for root, dirs, files in os.walk(CUDA_PATH):
                    for file_ in files:
                        if file_.lower().endswith(".dll"):
                            if root not in ONEAPI_DLLS:
                                ONEAPI_DLLS.add(root)
                            break

            try:
                ISPC_EXECUTABLE = os.environ["ISPC_EXECUTABLE"]
            except KeyError:
                ISPC_EXECUTABLE = None

            ISPC_DLLS = set([])
            if ISPC_EXECUTABLE is not None:
                ISPC_DLLS.add(os.path.dirname(ISPC_EXECUTABLE))

            # INCLUDE = os.path.join(PY_ROOT, "include")
            # LIB = os.path.join(PY_ROOT, "Lib")
            # SITEPACKAGES = os.path.join(PY_ROOT, "Lib", "site-packages")
            # LIBS = os.path.join(PY_ROOT, "libs")
            # SCRIPTS = os.path.join(PY_ROOT, "Scripts")

            dll_directories = [
                WIN_DLLS,
                PY_DLLS,
                VTK_DLLS,
                VULKAN_DLLS,
                CUDA_DLLS,
                ONEAPI_DLLS,
                ISPC_DLLS,
            ]

            print(f"WIN_DLLS: {WIN_DLLS}")
            print(f"PY_DLLS: {PY_DLLS}")
            print(f"VTK_DLLS: {VTK_DLLS}")
            print(f"VULKAN_DLLS: {VULKAN_DLLS}")
            print(f"CUDA_DLLS: {CUDA_DLLS}")
            print(f"ONEAPI_DLLS: {ONEAPI_DLLS}")
            print(f"ISPC_DLLS: {ISPC_DLLS}")

            for dll in dll_directories:
                if dll is not None:
                    for dll_ in dll:
                        os.add_dll_directory(dll_)

    import importlib

    # import vtkmodules.all
    all_m = importlib.import_module("vtkmodules.all")

    # import vtkmodules
    vtkmodules_m = importlib.import_module("vtkmodules")

    # make vtkmodules.all act as the vtkmodules package to support importing
    # other modules from vtkmodules package via `vtk`.
    all_m.__path__ = vtkmodules_m.__path__

    # replace old `vtk` module with the `all` package.
    sys.modules[__name__] = all_m

给出输出

❯ py
Python 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import vtk
WIN_DLLS: {'C:\WINDOWS\System32\downlevel'}
PY_DLLS: {'C:\Program Files\Python38\DLLs'}
VTK_DLLS: {'C:\VTK\bin\Lib\site-packages\mpi4py', 'C:\VTK\bin', 'C:\VTK\bin\Lib\site-packages\vtkmodules'}
VULKAN_DLLS: {'C:\VulkanSDK\1.2.182.0\Tools', 'C:\VulkanSDK\1.2.182.0\Tools32\styles', 'C:\VulkanSDK\1.2.182.0\Third-Party\Bin32', 'C:\VulkanSDK\1.2.182.0\Tools\styles', 'C:\VulkanSDK\1.2.182.0\Tools32\iconengines', 'C:\VulkanSDK\1.2.182.0\Tools\imageformats', 'C:\VulkanSDK\1.2.182.0\Tools\platforms', 'C:\VulkanSDK\1.2.182.0\Tools32\bearer', 'C:\VulkanSDK\1.2.182.0\Bin32', 'C:\VulkanSDK\1.2.182.0\Tools\bearer', 'C:\VulkanSDK\1.2.182.0\Bin', 'C:\VulkanSDK\1.2.182.0\Third-Party\Bin', 'C:\VulkanSDK\1.2.182.0\Tools32', 'C:\VulkanSDK\1.2.182.0\Tools32\imageformats', 'C:\VulkanSDK\1.2.182.0\Tools\iconengines', 'C:\VulkanSDK\1.2.182.0\Tools32\platforms'}
CUDA_DLLS: {'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\extras\visual_studio_integration\MSBuildExtensions', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\extras\demo_suite', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\extras\CUPTI\lib64', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\nvvm\bin', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\compute-sanitizer', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\libnvvp\plugins\org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20140603-1326', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\bin'}
ONEAPI_DLLS: {'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\extras\visual_studio_integration\MSBuildExtensions', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\extras\demo_suite', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\extras\CUPTI\lib64', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\nvvm\bin', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\compute-sanitizer', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\libnvvp\plugins\org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20140603-1326', 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\bin'}
ISPC_DLLS: {'C:\Program Files\ISPC\ispc-v1.16.1-windows\bin'}
Traceback (most recent call last):
  File "C:\Program Files\Python38\lib\site-packages\vtkmodules\__init__.py", line 13, in <module>
    from . import vtkCommonCore
ImportError: DLL load failed while importing vtkCommonCore: The specified module could not be found.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files\Python38\lib\site-packages\vtk.py", line 143, in <module>
    all_m = importlib.import_module("vtkmodules.all")
  File "C:\Program Files\Python38\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Program Files\Python38\lib\site-packages\vtkmodules\__init__.py", line 15, in <module>
    import _vtkmodules_static
ModuleNotFoundError: No module named '_vtkmodules_static'
>>>

这也不是答案 - 而是对我有用的简短方法。

我使用 Python 来自 python.org 的 3.8.8 - 应该没有任何区别。

我使用 VTK-9.0.1 - 在他们试图修复 os.add_dll_directory 问题之前。

我用的是Qt5.15.2

我没有使用 vcpkg

  1. 确保找到正确的 DLL
In [1]: import sys
In [2]: sys.path.insert(0, "c:/{VTK_BUILD_DIR}/bin/Lib/site-packages/")
  1. 确保它们已加载并且没有发生错误(有些是无声的)
In [5]: import os
In [6]: os.add_dll_directory("c:/{VTK_BUILD_DIR}/bin/Lib/site-packages/vtkmodules/")
In [7]: os.add_dll_directory("c:/{VTK_BUILD_DIR}/bin/Release/")
In [8]: os.add_dll_directory("c:/QT/Qt5.15/5.15.2/msvc2019_64/bin/")

This is made on top of an empty virtual environment, where only ipython is added.

我将生成的 CMake 文件放入 C:\VTK\build\,然后在 C:\VTK 中编译和安装,这就是 Python 找不到 DLL 的原因。我已更正 post 中的相应步骤,因此安装说明完整且正确。

参见第 Steps to Reproduce 部分,步骤 3