diff --git a/setup.py b/setup.py
index 4bcf02b395..4ac1fbe6da 100644
--- a/setup.py
+++ b/setup.py
@@ -19,52 +19,54 @@ featurizers_build = False
package_name = 'onnxruntime'
wheel_name_suffix = None
-# Any combination of the following arguments can be applied
-if '--use_featurizers' in sys.argv:
- featurizers_build = True
- sys.argv.remove('--use_featurizers')
+def parse_arg_remove_boolean(argv, arg_name):
+ arg_value = False
+ if arg_name in sys.argv:
+ arg_value = True
+ argv.remove(arg_name)
-if '--nightly_build' in sys.argv:
+ return arg_value
+
+def parse_arg_remove_string(argv, arg_name_equal):
+ arg_value = None
+ for arg in sys.argv[1:]:
+ if arg.startswith(arg_name_equal):
+ arg_value = arg[len(arg_name_equal):]
+ sys.argv.remove(arg)
+ break
+
+ return arg_value
+
+# Any combination of the following arguments can be applied
+featurizers_build = parse_arg_remove_boolean(sys.argv, '--use_featurizers')
+
+if parse_arg_remove_boolean(sys.argv, '--nightly_build'):
package_name = 'ort-nightly'
nightly_build = True
- sys.argv.remove('--nightly_build')
-for arg in sys.argv[1:]:
- if arg.startswith("--wheel_name_suffix="):
- wheel_name_suffix = arg[len("--wheel_name_suffix="):]
-
- sys.argv.remove(arg)
-
- break
+wheel_name_suffix = parse_arg_remove_string(sys.argv, '--wheel_name_suffix=')
+cuda_version = None
# The following arguments are mutually exclusive
-if '--use_tensorrt' in sys.argv:
+if parse_arg_remove_boolean(sys.argv, '--use_tensorrt'):
package_name = 'onnxruntime-gpu-tensorrt' if not nightly_build else 'ort-trt-nightly'
- sys.argv.remove('--use_tensorrt')
-elif '--use_cuda' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_cuda'):
package_name = 'onnxruntime-gpu' if not nightly_build else 'ort-gpu-nightly'
- sys.argv.remove('--use_cuda')
-elif '--use_openvino' in sys.argv:
+ cuda_version = parse_arg_remove_string(sys.argv, '--cuda_version=')
+elif parse_arg_remove_boolean(sys.argv, '--use_openvino'):
package_name = 'onnxruntime-openvino'
- sys.argv.remove('--use_openvino')
-elif '--use_dnnl' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_dnnl'):
package_name = 'onnxruntime-dnnl'
- sys.argv.remove('--use_dnnl')
-elif '--use_nuphar' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_nuphar'):
package_name = 'onnxruntime-nuphar'
- sys.argv.remove('--use_nuphar')
-elif '--use_vitisai' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_vitisai'):
package_name = 'onnxruntime-vitisai'
- sys.argv.remove('--use_vitisai')
-elif '--use_acl' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_acl'):
package_name = 'onnxruntime-acl'
- sys.argv.remove('--use_acl')
-elif '--use_armnn' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_armnn'):
package_name = 'onnxruntime-armnn'
- sys.argv.remove('--use_armnn')
-elif '--use_dml' in sys.argv:
+elif parse_arg_remove_boolean(sys.argv, '--use_dml'):
package_name = 'onnxruntime-dml'
- sys.argv.remove('--use_dml')
# PEP 513 defined manylinux1_x86_64 and manylinux1_i686
# PEP 571 defined manylinux2010_x86_64 and manylinux2010_i686
@@ -234,12 +236,25 @@ packages = [
requirements_file = "requirements.txt"
-if '--enable_training' in sys.argv:
+local_version = None
+enable_training = parse_arg_remove_boolean(sys.argv, '--enable_training')
+if enable_training:
packages.extend(['onnxruntime.training',
'onnxruntime.training.amp',
'onnxruntime.training.optim'])
- sys.argv.remove('--enable_training')
requirements_file = "requirements-training.txt"
+ # with training, we want to follow this naming convention:
+ # stable:
+ # onnxruntime-training-1.7.0+cu111-cp36-cp36m-linux_x86_64.whl
+ # nightly:
+ # onnxruntime-training-1.7.0.dev20210408+cu111-cp36-cp36m-linux_x86_64.whl
+ # this is needed immediately by pytorch/ort so that the user is able to
+ # install an onnxruntime training package with matching torch cuda version.
+ package_name = 'onnxruntime-training'
+ if cuda_version and not nightly_build:
+ # removing '.' to make Cuda version number in the same form as Pytorch.
+ cuda_version = cuda_version.replace('.', '')
+ local_version = '+cu' + cuda_version
package_data = {}
data_files = []
@@ -295,21 +310,38 @@ version_number = ''
with open('VERSION_NUMBER') as f:
version_number = f.readline().strip()
if nightly_build:
- #https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables
+ # https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables
build_suffix = environ.get('BUILD_BUILDNUMBER')
if build_suffix is None:
- #The following line is only for local testing
- build_suffix = str(datetime.datetime.now().date().strftime("%Y%m%d"))
+ # The following line is only for local testing
+ build_suffix = str(datetime.datetime.now().date().strftime("%Y%m%d"))
else:
- build_suffix = build_suffix.replace('.','')
+ build_suffix = build_suffix.replace('.', '')
+
+ if enable_training:
+ from packaging import version
+ from packaging.version import Version
+ # with training package, we need to bump up version minor number so that
+ # nightly releases take precedence over the latest release when --pre is used during pip install.
+ # eventually this shall be the behavior of all onnxruntime releases.
+ # alternatively we may bump up version number right after every release.
+ ort_version = version.parse(version_number)
+ if isinstance(ort_version, Version):
+ version_number = '{major}.{minor}.{macro}'.format(
+ major=ort_version.major,
+ minor=ort_version.minor + 1,
+ macro=ort_version.micro)
version_number = version_number + ".dev" + build_suffix
+if local_version:
+ version_number = version_number + local_version
+
if wheel_name_suffix:
package_name = "{}_{}".format(package_name, wheel_name_suffix)
cmd_classes = {}
-if bdist_wheel is not None :
+if bdist_wheel is not None:
cmd_classes['bdist_wheel'] = bdist_wheel
cmd_classes['build_ext'] = build_ext
diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py
index 7aa77a3363..ad72044afd 100644
--- a/tools/ci_build/build.py
+++ b/tools/ci_build/build.py
@@ -1474,7 +1474,7 @@ def run_nodejs_tests(nodejs_binding_dir):
def build_python_wheel(
- source_dir, build_dir, configs, use_cuda, use_dnnl,
+ source_dir, build_dir, configs, use_cuda, cuda_version, use_dnnl,
use_tensorrt, use_openvino, use_nuphar, use_vitisai, use_acl, use_armnn, use_dml,
wheel_name_suffix, enable_training, nightly_build=False, featurizers_build=False, use_ninja=False):
for config in configs:
@@ -1510,6 +1510,8 @@ def build_python_wheel(
args.append('--use_tensorrt')
elif use_cuda:
args.append('--use_cuda')
+ if cuda_version:
+ args.append('--cuda_version={}'.format(cuda_version))
elif use_openvino:
args.append('--use_openvino')
elif use_dnnl:
@@ -2019,6 +2021,7 @@ def main():
build_dir,
configs,
args.use_cuda,
+ args.cuda_version,
args.use_dnnl,
args.use_tensorrt,
args.use_openvino,
diff --git a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline.yml
index c8ad072f1d..c5568e5381 100644
--- a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline.yml
+++ b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline.yml
@@ -3,7 +3,7 @@ trigger: none
stages:
- template: templates/py-packaging-stage.yml
parameters:
- build_py_parameters: --enable_training --wheel_name_suffix=training
+ build_py_parameters: --enable_training
enable_linux_cpu: false
enable_linux_gpu: false
enable_linux_gpu_training: true
diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml
index f292a4d74a..b22d1967d6 100644
--- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml
+++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml
@@ -235,6 +235,7 @@ stages:
# Python39:
# PythonVersion: '3.9'
steps:
+
- checkout: self
clean: true
submodules: recursive
@@ -276,7 +277,7 @@ stages:
--cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-8/root/usr/bin/cc PYTHON_INCLUDE_DIR=$(PythonManylinuxIncludeDir) PYTHON_LIBRARY=/usr/lib64/librt.so \
--use_cuda --cuda_version=11.1 --cuda_home=/usr/local/cuda-11.1 --cudnn_home=/usr/local/cuda-11.1
workingDirectory: $(Build.SourcesDirectory)
-
+
- task: CopyFiles@2
displayName: 'Copy Python Wheel to: $(Build.ArtifactStagingDirectory)'
inputs:
@@ -321,27 +322,53 @@ stages:
displayName: 'sudo apt-get install python3-pip python-dev'
- script: |
- python3 -m pip install twine
- displayName: 'python3 -m pip install twine'
+ python3 -m pip install azure-storage-blob==2.1.0
+ displayName: 'python3 -m pip install azure-storage-blob==2.1.0'
timeoutInMinutes: 20
- # this block does not work because TwineAuthenticate@1 will trigger cleanup of $(PYPIRC_PATH)
- # at the end of pipeline execution. Because $(PYPIRC_PATH) is already cleaned by clean-agent-build-directory-step.yml
- # the cleanup task for TwineAuthenticate@1 will fail. For this reason, we cannot used TwineAuthenticate@1.
- # - task: TwineAuthenticate@1
- # inputs:
- # artifactFeed: 'lotus/ort-gpu-nightly-training-feed'
+ - task: AzureCLI@2
+ inputs:
+ azureSubscription: 'AIInfraBuildOnnxRuntimeOSS'
+ scriptType: 'bash'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ files=($(Build.ArtifactStagingDirectory)/Release/dist/*.whl) && \
+ echo ${files[0]} && \
+ tools/ci_build/upload_python_package_to_azure_storage.py \
+ --python_wheel_path ${files[0]} \
+ --account_name onnxruntimepackages \
+ --account_key $(orttrainingpackagestorageaccountkey) \
+ --container_name '$web'
+ condition: succeededOrFailed()
+ displayName:
# - script: |
- # python3 -m twine upload -r ort-gpu-nightly-training-feed --config-file $(PYPIRC_PATH) $(Build.ArtifactStagingDirectory)/Release/dist/*.whl
- # displayName: 'python3 -m twine upload -r ort-gpu-nightly-training-feed $(Build.ArtifactStagingDirectory)/Release/dist/*.whl'
+ # sudo apt-get update
+ # sudo apt-get install python3-pip python-dev
+ # displayName: 'sudo apt-get install python3-pip python-dev'
+
+ # - script: |
+ # python3 -m pip install twine
+ # displayName: 'python3 -m pip install twine'
# timeoutInMinutes: 20
- - script: |
- python3 -m twine upload -r ORT-Nightly --repository-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT-Nightly/pypi/upload \
- --username $(ortpypitrainingnightlyusername) --password $(aiinfrapypifeedpassword) $(Build.ArtifactStagingDirectory)/Release/dist/*.whl
- displayName: 'python3 -m twine upload $(Build.ArtifactStagingDirectory)/Release/dist/*.whl'
- timeoutInMinutes: 20
+ # # this block does not work because TwineAuthenticate@1 will trigger cleanup of $(PYPIRC_PATH)
+ # # at the end of pipeline execution. Because $(PYPIRC_PATH) is already cleaned by clean-agent-build-directory-step.yml
+ # # the cleanup task for TwineAuthenticate@1 will fail. For this reason, we cannot used TwineAuthenticate@1.
+ # # - task: TwineAuthenticate@1
+ # # inputs:
+ # # artifactFeed: 'lotus/ort-gpu-nightly-training-feed'
+
+ # # - script: |
+ # # python3 -m twine upload -r ort-gpu-nightly-training-feed --config-file $(PYPIRC_PATH) $(Build.ArtifactStagingDirectory)/Release/dist/*.whl
+ # # displayName: 'python3 -m twine upload -r ort-gpu-nightly-training-feed $(Build.ArtifactStagingDirectory)/Release/dist/*.whl'
+ # # timeoutInMinutes: 20
+
+ # - script: |
+ # python3 -m twine upload -r ORT-Nightly --repository-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT-Nightly/pypi/upload \
+ # --username $(ortpypitrainingnightlyusername) --password $(aiinfrapypifeedpassword) $(Build.ArtifactStagingDirectory)/Release/dist/*.whl
+ # displayName: 'python3 -m twine upload $(Build.ArtifactStagingDirectory)/Release/dist/*.whl'
+ # timeoutInMinutes: 20
- template: component-governance-component-detection-steps.yml
parameters:
diff --git a/tools/ci_build/upload_python_package_to_azure_storage.py b/tools/ci_build/upload_python_package_to_azure_storage.py
new file mode 100755
index 0000000000..c96bfbc205
--- /dev/null
+++ b/tools/ci_build/upload_python_package_to_azure_storage.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import os
+import argparse
+from azure.storage.blob import BlockBlobService, ContentSettings
+
+
+def upload_whl(python_wheel_path, account_name, account_key, container_name):
+ block_blob_service = BlockBlobService(
+ account_name=account_name,
+ account_key=account_key
+ )
+
+ blob_name = os.path.basename(python_wheel_path)
+ block_blob_service.create_blob_from_path(container_name, blob_name, python_wheel_path)
+
+ html_blob_name = 'onnxruntime_nightly.html'
+ download_path_to_html = "./onnxruntime_nightly.html"
+ block_blob_service.get_blob_to_path(container_name, html_blob_name, download_path_to_html)
+
+ blob_name_plus_replaced = blob_name.replace('+', '%2B')
+ with open(download_path_to_html) as f:
+ lines = f.read().splitlines()
+
+ new_line = '{blobname}
'.format(blobname=blob_name_plus_replaced)
+ lines.append(new_line)
+ lines.sort()
+
+ with open(download_path_to_html, 'w') as f:
+ for item in lines:
+ f.write("%s\n" % item)
+
+ content_settings = ContentSettings(content_type='text/html')
+ block_blob_service.create_blob_from_path(
+ container_name,
+ html_blob_name,
+ download_path_to_html,
+ content_settings=content_settings)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Upload python whl to azure storage.")
+
+ parser.add_argument("--python_wheel_path", type=str, help="path to python wheel")
+ parser.add_argument("--account_name", type=str, help="account name")
+ parser.add_argument("--account_key", type=str, help="account key")
+ parser.add_argument("--container_name", type=str, help="container name")
+
+ # TODO: figure out a way to secure args.account_key to prevent later code changes
+ # that may accidentally print out it to the console.
+ args = parser.parse_args()
+
+ upload_whl(args.python_wheel_path, args.account_name, args.account_key, args.container_name)