Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python] Windows wheels that support GPUs via OpenCL #3403

Merged
merged 70 commits into from
Dec 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
b1841bd
Add specialized OpenCL/Python package build path
tpboudreau May 27, 2020
27dffcb
Refer to upstream OpenCL repository
tpboudreau Jun 2, 2020
2958084
Reset build job count in setup.py
tpboudreau Jun 3, 2020
eeb1104
Run test for dual CPU/GPU code in CI
itamarst Jun 3, 2020
1494730
Merge remote-tracking branch 'tpboudreau/build_python_package_library…
itamarst Jun 3, 2020
519a5b9
TEMPORARY: refer to OpenCL fork to ensure Linux CI builds succeed
tpboudreau Jun 3, 2020
239dc49
Try switching to OpenCL 2.0
itamarst Jun 3, 2020
d8241b7
Add --opencl-python-pacakge option to wheel
itamarst Jun 3, 2020
e21fbc9
Fix some typos.
itamarst Jun 3, 2020
84b6804
Remove intermediate cmake target
tpboudreau Jun 3, 2020
ec4b3f4
Restrict OpenCL headers to documented API version
tpboudreau Jun 4, 2020
c5263c3
Merge base branch in again
itamarst Jun 5, 2020
ed65913
Refresh the environment after installation
itamarst Jun 5, 2020
3b0b910
Try testing with two processes
itamarst Jun 5, 2020
1fc7878
Use command line definition to activate integrated build
tpboudreau Jun 8, 2020
bf226e3
Try newer OpenCL runtime
itamarst Jun 9, 2020
3e57182
If we hit OpenCL code path that's good enough
itamarst Jun 9, 2020
8e66b4e
Merge branch 'master' into build_python_package_library
tpboudreau Jun 9, 2020
7747d63
Make tests run correctly
itamarst Jun 9, 2020
ed344fb
Correct directory
itamarst Jun 9, 2020
af176a6
Flag reference to unofficial repo with FIXME
tpboudreau Jun 9, 2020
e0c71cb
Merge branch 'master' into build_python_package_library
tpboudreau Jun 30, 2020
81e6773
Merge branch 'master' into build_python_package_library
tpboudreau Aug 10, 2020
4dac9f5
Merge branch 'master' into build_python_package_library (with conflic…
tpboudreau Aug 27, 2020
180c929
TEMPORARY: update private repo tag for dependency
tpboudreau Aug 27, 2020
3616acc
Merge remote-tracking branch 'tpboudreau/build_python_package_library…
itamarst Sep 2, 2020
2bf13b9
Merge remote-tracking branch 'microsoft/master' into windows-gpu-buil…
itamarst Sep 22, 2020
7ce6028
Further post-merge fixes.
itamarst Sep 22, 2020
d9ad5a7
Fix attribute name.
itamarst Sep 23, 2020
69381fd
Reformat with black.
itamarst Sep 23, 2020
67f4cb8
Rewrite config.h before library compilation for Windows wheel
tpboudreau Nov 2, 2020
c9b94a6
Merge branch 'master' into windows-gpu-builds-take-3
tpboudreau Nov 2, 2020
25b1d88
Run dual cpu/gpu test once only for Windows bdist CI
tpboudreau Nov 3, 2020
6df3eb6
Avoid C API tests when building gpu library for wheel
tpboudreau Nov 4, 2020
67f2540
TEMPORARY -- add clinfo tool to vm for debugging
tpboudreau Nov 4, 2020
4f04a94
Increase compilation logging
tpboudreau Nov 4, 2020
1c28c46
Rename OpenCL registry parameter after driver installation
tpboudreau Nov 4, 2020
477fd42
Install legacy OpenCL runtime
tpboudreau Nov 6, 2020
f6d0dee
...
tpboudreau Nov 6, 2020
5fd426b
Remove config.h change, clinfo installation, latest opencl runtime re…
tpboudreau Nov 10, 2020
4d3a724
Add explicit script exit
tpboudreau Nov 10, 2020
7403314
Merge branch 'master' into windows-gpu-builds-take-3
tpboudreau Nov 17, 2020
97489e3
revert to 18.1 intel driver
tpboudreau Nov 17, 2020
cbfec02
Run test_dual.py in two different modes
tpboudreau Nov 19, 2020
78bd0a2
Revert "Run test_dual.py in two different modes"
tpboudreau Nov 24, 2020
9f4c453
Remove unused expected failure test
tpboudreau Nov 24, 2020
011fc9a
Merge from master with conflict resolution
tpboudreau Dec 10, 2020
48f25fa
Install OpenCL in separate powershell script
tpboudreau Dec 11, 2020
a38977f
fix setup.py imports
tpboudreau Dec 11, 2020
b00d907
activate conda env after session update
tpboudreau Dec 11, 2020
7e8c5bc
separate update functions; exit opencl installation on error
tpboudreau Dec 11, 2020
e721d95
nothing; start pipeline
tpboudreau Dec 11, 2020
ae74d0e
download from original source
tpboudreau Dec 11, 2020
cd50a78
specify tls version for installer download
tpboudreau Dec 11, 2020
41915de
eliminate variable from command
tpboudreau Dec 11, 2020
c3031b6
download opencl installer in parts
tpboudreau Dec 11, 2020
e7d7d2f
Merge branch 'master' into windows-gpu-builds-take-3
tpboudreau Dec 11, 2020
bcaceb8
remove duplicate setup.py command class entry
tpboudreau Dec 12, 2020
9396486
download smaller parts
tpboudreau Dec 12, 2020
88b9c49
remove redundant bdist wheel class
tpboudreau Dec 12, 2020
54a2eb4
Import chocolatey modules and use RefreshEnv
tpboudreau Dec 12, 2020
cf52ec0
insert pipeline cache for opencl installer
tpboudreau Dec 13, 2020
817065c
rerun to ensure pipeline cache hit
tpboudreau Dec 13, 2020
7abc286
add comments, test another pipeline cache hit
tpboudreau Dec 13, 2020
a119912
remove cache task; download full installer file from new location
tpboudreau Dec 15, 2020
2f13375
try another installer download timing
tpboudreau Dec 15, 2020
761a48c
reinsert pipeline cache
tpboudreau Dec 15, 2020
822bb34
retain cache task; download full file on cache miss
tpboudreau Dec 15, 2020
f456487
test cache hit again
tpboudreau Dec 15, 2020
29932a7
remove todo
tpboudreau Dec 16, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .ci/install_opencl.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

Write-Output "Installing OpenCL CPU platform"

$cache = "$env:PIPELINE_WORKSPACE\opencl_windows-amd_cpu-v3_0_130_135"
$installer = "AMD-APP-SDKInstaller-v3.0.130.135-GA-windows-F-x64.exe"

if ($env:OPENCL_INSTALLER_FOUND -ne 'true') {
# Pipeline cache miss; download OpenCL platform installer executable into workspace cache

Write-Output "Downloading OpenCL platform installer"
Invoke-WebRequest -OutFile "$installer" -Uri "https://github.com/microsoft/LightGBM/releases/download/v2.0.12/$installer"

Write-Output "Caching OpenCL platform installer"
New-Item $cache -ItemType Directory | Out-Null
Move-Item -Path "$installer" -Destination "$cache\$installer" | Out-Null

if (Test-Path "$cache\$installer") {
Write-Output "Successfully downloaded OpenCL platform installer"
} else {
Write-Output "Unable to download OpenCL platform installer"
Write-Output "Setting EXIT"
$host.SetShouldExit(-1)
Exit -1
}
}

# Install OpenCL platform from installer executable expected in workspace cache

Write-Output "Running OpenCL installer"
Invoke-Command -ScriptBlock {Start-Process "$cache\$installer" -ArgumentList '/S /V"/quiet /norestart /passive /log opencl.log"' -Wait}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question. What does this syntax mean? /V" ... opencl.log". I mean double quotes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The installer package has a program inside a program: the outer (extractor) program takes the /S and /V arguments. The value of the /V argument is the list of arguments you want passed to the inner (installer) program. You need to quote them to make sure they're all passed together, not interpreted as (unrecognized) arguments to the outer program. Since the ArgumentList is already single-quoted, you have to use double-quotes for the interior quotes.


$property = Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenCL\Vendors
if ($property -eq $null) {
Write-Output "Unable to install OpenCL CPU platform"
Write-Output "OpenCL installation log:"
Get-Content "opencl.log"
Write-Output "Setting EXIT"
$host.SetShouldExit(-1)
Exit -1
} else {
Write-Output "Successfully installed OpenCL CPU platform"
Write-Output "Current OpenCL drivers:"
Write-Output $property
}

24 changes: 20 additions & 4 deletions .ci/test_windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ function Check-Output {
}
}

# Import the Chocolatey profile module so that the RefreshEnv command
# invoked below properly updates the current PowerShell session enviroment.
$module = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
Import-Module "$module" ; Check-Output $?

# unify environment variables for Azure devops and AppVeyor
if (Test-Path env:APPVEYOR) {
$env:APPVEYOR = "true"
Expand All @@ -23,9 +28,9 @@ conda activate
conda config --set always_yes yes --set changeps1 no
conda update -q -y conda
conda create -q -y -n $env:CONDA_ENV python=$env:PYTHON_VERSION joblib matplotlib numpy pandas psutil pytest python-graphviz scikit-learn scipy ; Check-Output $?
conda activate $env:CONDA_ENV

if ($env:TASK -eq "regular") {
conda activate $env:CONDA_ENV
mkdir $env:BUILD_SOURCESDIRECTORY/build; cd $env:BUILD_SOURCESDIRECTORY/build
cmake -A x64 .. ; cmake --build . --target ALL_BUILD --config Release ; Check-Output $?
cd $env:BUILD_SOURCESDIRECTORY/python-package
Expand All @@ -34,6 +39,7 @@ if ($env:TASK -eq "regular") {
cp $env:BUILD_SOURCESDIRECTORY/Release/lightgbm.exe $env:BUILD_ARTIFACTSTAGINGDIRECTORY
}
elseif ($env:TASK -eq "sdist") {
conda activate $env:CONDA_ENV
cd $env:BUILD_SOURCESDIRECTORY/python-package
python setup.py sdist --formats gztar ; Check-Output $?
cd dist; pip install @(Get-ChildItem *.gz) -v ; Check-Output $?
Expand All @@ -48,11 +54,17 @@ elseif ($env:TASK -eq "sdist") {
cp $env:BUILD_SOURCESDIRECTORY/build/lightgbmlib.jar $env:BUILD_ARTIFACTSTAGINGDIRECTORY/lightgbmlib_win.jar
}
elseif ($env:TASK -eq "bdist") {
RefreshEnv
Write-Output "Current OpenCL drivers:"
Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenCL\Vendors

conda activate $env:CONDA_ENV
cd $env:BUILD_SOURCESDIRECTORY/python-package
python setup.py bdist_wheel --plat-name=win-amd64 --python-tag py3 ; Check-Output $?
cd dist; pip install @(Get-ChildItem *.whl) ; Check-Output $?
python setup.py bdist_wheel --integrated-opencl --plat-name=win-amd64 --python-tag py3 ; Check-Output $?
cd dist; pip install --user @(Get-ChildItem *.whl) ; Check-Output $?
cp @(Get-ChildItem *.whl) $env:BUILD_ARTIFACTSTAGINGDIRECTORY
} elseif (($env:APPVEYOR -eq "true") -and ($env:TASK -eq "python")) {
conda activate $env:CONDA_ENV
cd $env:BUILD_SOURCESDIRECTORY\python-package
if ($env:COMPILER -eq "MINGW") {
python setup.py install --mingw ; Check-Output $?
Expand All @@ -62,9 +74,13 @@ elseif ($env:TASK -eq "bdist") {
}

if (($env:TASK -eq "sdist") -or (($env:APPVEYOR -eq "true") -and ($env:TASK -eq "python"))) {
# cannot test C API with "sdist" task
$tests = $env:BUILD_SOURCESDIRECTORY + "/tests/python_package_test"
} elseif ($env:TASK -eq "bdist") {
$tests = $env:BUILD_SOURCESDIRECTORY + "/tests"
# Make sure we can do both CPU and GPU; see tests/python_package_test/test_dual.py
$env:LIGHTGBM_TEST_DUAL_CPU_GPU = "1"
} else {
# cannot test C API with "sdist" task
$tests = $env:BUILD_SOURCESDIRECTORY + "/tests"
}
pytest $tests ; Check-Output $?
Expand Down
11 changes: 11 additions & 0 deletions .vsts-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ jobs:
Write-Host "##vso[task.prependpath]$env:CONDA\Scripts"
Write-Host "##vso[task.setvariable variable=AZURE]true"
displayName: 'Set Variables'
- task: Cache@2
inputs:
key: '"opencl.windows" | "amd.cpu" | "v3.0.130.135" | "1"'
path: $(Pipeline.Workspace)/opencl_windows-amd_cpu-v3_0_130_135
cacheHitVar: OPENCL_INSTALLER_FOUND
condition: eq(variables.TASK, 'bdist')
displayName: 'Cache OpenCL'
- script: |
cmd /c "powershell -ExecutionPolicy Bypass -File %BUILD_SOURCESDIRECTORY%/.ci/install_opencl.ps1"
condition: eq(variables.TASK, 'bdist')
displayName: 'Install OpenCL'
- script: |
cmd /c "conda init powershell"
cmd /c "powershell -ExecutionPolicy Bypass -File %BUILD_SOURCESDIRECTORY%/.ci/test_windows.ps1"
Expand Down
8 changes: 2 additions & 6 deletions python-package/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,10 @@ def clear_path(path):

def silent_call(cmd, raise_error=False, error_msg=''):
try:
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
with open(LOG_PATH, "ab") as log:
log.write(output)
subprocess.check_call(cmd, stderr=log, stdout=log)
return 0
except Exception as err:
if isinstance(err, subprocess.CalledProcessError):
with open(LOG_PATH, "ab") as log:
log.write(err.output)
if raise_error:
raise Exception("\n".join((error_msg, LOG_NOTICE)))
return 1
Expand Down Expand Up @@ -185,7 +181,7 @@ def compile_cpp(use_mingw=False, use_gpu=False, use_cuda=False, use_mpi=False,
arch = "Win32" if bit32 else "x64"
vs_versions = ("Visual Studio 16 2019", "Visual Studio 15 2017", "Visual Studio 14 2015")
for vs in vs_versions:
logger.info("Starting to compile with %s." % vs)
logger.info("Starting to compile with %s (%s).", vs, arch)
status = silent_call(cmake_cmd + ["-G", vs, "-A", arch])
if status == 0:
break
Expand Down
36 changes: 36 additions & 0 deletions tests/python_package_test/test_dual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Tests for dual GPU+CPU support."""

import os
import pytest

import lightgbm as lgb
import numpy as np
from lightgbm.basic import LightGBMError


@pytest.mark.skipif(
os.environ.get("LIGHTGBM_TEST_DUAL_CPU_GPU", None) is None,
reason="Only run if appropriate env variable is set",
)
def test_cpu_works():
"""If compiled appropriately, the same installation will support both GPU and CPU."""
data = np.random.rand(500, 10)
label = np.random.randint(2, size=500)
validation_data = train_data = lgb.Dataset(data, label=label)

param = {"verbosity": 2, "num_leaves": 31, "objective": "binary", "device": "cpu"}
gbm = lgb.train(param, train_data, 10, valid_sets=[validation_data])


@pytest.mark.skipif(
os.environ.get("LIGHTGBM_TEST_DUAL_CPU_GPU", None) is None,
reason="Only run if appropriate env variable is set",
)
def test_gpu_works():
"""If compiled appropriately, the same installation will support both GPU and CPU."""
data = np.random.rand(500, 10)
label = np.random.randint(2, size=500)
validation_data = train_data = lgb.Dataset(data, label=label)

param = {"verbosity": 2, "num_leaves": 31, "objective": "binary", "device": "gpu"}
gbm = lgb.train(param, train_data, 10, valid_sets=[validation_data])