setup.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. """
  2. Copyright 2020 The Microsoft DeepSpeed Team
  3. DeepSpeed library
  4. Create a new wheel via the following command: python setup.py bdist_wheel
  5. The wheel will be located at: dist/*.whl
  6. """
  7. import os
  8. import shutil
  9. import subprocess
  10. import warnings
  11. from setuptools import setup, find_packages
  12. import time
  13. try:
  14. import torch
  15. from torch.utils.cpp_extension import BuildExtension
  16. except ImportError:
  17. raise ImportError('Unable to import torch, please visit https://pytorch.org/ '
  18. 'to see how to properly install torch on your system.')
  19. from op_builder import ALL_OPS, get_default_compute_capatabilities
  20. def fetch_requirements(path):
  21. with open(path, 'r') as fd:
  22. return [r.strip() for r in fd.readlines()]
  23. install_requires = fetch_requirements('requirements/requirements.txt')
  24. extras_require = {
  25. '1bit_adam': fetch_requirements('requirements/requirements-1bit-adam.txt'),
  26. 'readthedocs': fetch_requirements('requirements/requirements-readthedocs.txt'),
  27. 'dev': fetch_requirements('requirements/requirements-dev.txt'),
  28. }
  29. # If MPI is available add 1bit-adam requirements
  30. if torch.cuda.is_available():
  31. if shutil.which('ompi_info') or shutil.which('mpiname'):
  32. cupy = f"cupy-cuda{torch.version.cuda.replace('.','')[:3]}"
  33. extras_require['1bit_adam'].append(cupy)
  34. # Make an [all] extra that installs all needed dependencies
  35. all_extras = set()
  36. for extra in extras_require.items():
  37. for req in extra[1]:
  38. all_extras.add(req)
  39. extras_require['all'] = list(all_extras)
  40. cmdclass = {}
  41. # For any pre-installed ops force disable ninja
  42. cmdclass['build_ext'] = BuildExtension.with_options(use_ninja=False)
  43. TORCH_MAJOR = torch.__version__.split('.')[0]
  44. TORCH_MINOR = torch.__version__.split('.')[1]
  45. if not torch.cuda.is_available():
  46. # Fix to allow docker builds, similar to https://github.com/NVIDIA/apex/issues/486
  47. print(
  48. "[WARNING] Torch did not find cuda available, if cross-compiling or running with cpu only "
  49. "you can ignore this message. Adding compute capability for Pascal, Volta, and Turing "
  50. "(compute capabilities 6.0, 6.1, 6.2)")
  51. if os.environ.get("TORCH_CUDA_ARCH_LIST", None) is None:
  52. os.environ["TORCH_CUDA_ARCH_LIST"] = get_default_compute_capatabilities()
  53. ext_modules = []
  54. # Default to pre-install kernels to false so we rely on JIT
  55. BUILD_OP_DEFAULT = int(os.environ.get('DS_BUILD_OPS', 0))
  56. print(f"DS_BUILD_OPS={BUILD_OP_DEFAULT}")
  57. def command_exists(cmd):
  58. result = subprocess.Popen(f'type {cmd}', stdout=subprocess.PIPE, shell=True)
  59. return result.wait() == 0
  60. def op_enabled(op_name):
  61. assert hasattr(ALL_OPS[op_name], 'BUILD_VAR'), \
  62. f"{op_name} is missing BUILD_VAR field"
  63. env_var = ALL_OPS[op_name].BUILD_VAR
  64. return int(os.environ.get(env_var, BUILD_OP_DEFAULT))
  65. install_ops = dict.fromkeys(ALL_OPS.keys(), False)
  66. for op_name, builder in ALL_OPS.items():
  67. op_compatible = builder.is_compatible()
  68. # If op is compatible update install reqs so it can potentially build/run later
  69. if op_compatible:
  70. reqs = builder.python_requirements()
  71. install_requires += builder.python_requirements()
  72. # If op install enabled, add builder to extensions
  73. if op_enabled(op_name) and op_compatible:
  74. install_ops[op_name] = op_enabled(op_name)
  75. ext_modules.append(builder.builder())
  76. compatible_ops = {op_name: op.is_compatible() for (op_name, op) in ALL_OPS.items()}
  77. print(f'Install Ops={install_ops}')
  78. # Write out version/git info
  79. git_hash_cmd = "git rev-parse --short HEAD"
  80. git_branch_cmd = "git rev-parse --abbrev-ref HEAD"
  81. if command_exists('git') and 'DS_BUILD_STRING' not in os.environ:
  82. try:
  83. result = subprocess.check_output(git_hash_cmd, shell=True)
  84. git_hash = result.decode('utf-8').strip()
  85. result = subprocess.check_output(git_branch_cmd, shell=True)
  86. git_branch = result.decode('utf-8').strip()
  87. except subprocess.CalledProcessError:
  88. git_hash = "unknown"
  89. git_branch = "unknown"
  90. else:
  91. git_hash = "unknown"
  92. git_branch = "unknown"
  93. # Parse the DeepSpeed version string from version.txt
  94. version_str = open('version.txt', 'r').read().strip()
  95. # Build specifiers like .devX can be added at install time. Otherwise, add the git hash.
  96. # example: DS_BUILD_STR=".dev20201022" python setup.py sdist bdist_wheel
  97. # Building wheel for distribution, update version file
  98. if 'DS_BUILD_STRING' in os.environ:
  99. # Build string env specified, probably building for distribution
  100. with open('build.txt', 'w') as fd:
  101. fd.write(os.environ.get('DS_BUILD_STRING'))
  102. version_str += os.environ.get('DS_BUILD_STRING')
  103. elif os.path.isfile('build.txt'):
  104. # build.txt exists, probably installing from distribution
  105. with open('build.txt', 'r') as fd:
  106. version_str += fd.read().strip()
  107. else:
  108. # None of the above, probably installing from source
  109. version_str += f'+{git_hash}'
  110. torch_version = ".".join([TORCH_MAJOR, TORCH_MINOR])
  111. # Set cuda_version to 0.0 if cpu-only
  112. cuda_version = "0.0"
  113. if torch.version.cuda is not None:
  114. cuda_version = ".".join(torch.version.cuda.split('.')[:2])
  115. torch_info = {"version": torch_version, "cuda_version": cuda_version}
  116. print(f"version={version_str}, git_hash={git_hash}, git_branch={git_branch}")
  117. with open('deepspeed/git_version_info_installed.py', 'w') as fd:
  118. fd.write(f"version='{version_str}'\n")
  119. fd.write(f"git_hash='{git_hash}'\n")
  120. fd.write(f"git_branch='{git_branch}'\n")
  121. fd.write(f"installed_ops={install_ops}\n")
  122. fd.write(f"compatible_ops={compatible_ops}\n")
  123. fd.write(f"torch_info={torch_info}\n")
  124. print(f'install_requires={install_requires}')
  125. print(f'compatible_ops={compatible_ops}')
  126. print(f'ext_modules={ext_modules}')
  127. # Parse README.md to make long_description for PyPI page.
  128. thisdir = os.path.abspath(os.path.dirname(__file__))
  129. with open(os.path.join(thisdir, 'README.md'), encoding='utf-8') as fin:
  130. readme_text = fin.read()
  131. start_time = time.time()
  132. setup(name='deepspeed',
  133. version=version_str,
  134. description='DeepSpeed library',
  135. long_description=readme_text,
  136. long_description_content_type='text/markdown',
  137. author='DeepSpeed Team',
  138. author_email='deepspeed@microsoft.com',
  139. url='http://deepspeed.ai',
  140. install_requires=install_requires,
  141. extras_require=extras_require,
  142. packages=find_packages(exclude=["docker",
  143. "third_party"]),
  144. include_package_data=True,
  145. scripts=[
  146. 'bin/deepspeed',
  147. 'bin/deepspeed.pt',
  148. 'bin/ds',
  149. 'bin/ds_ssh',
  150. 'bin/ds_report',
  151. 'bin/ds_elastic'
  152. ],
  153. classifiers=[
  154. 'Programming Language :: Python :: 3.6',
  155. 'Programming Language :: Python :: 3.7',
  156. 'Programming Language :: Python :: 3.8'
  157. ],
  158. license='MIT',
  159. ext_modules=ext_modules,
  160. cmdclass=cmdclass)
  161. end_time = time.time()
  162. print(f'deepspeed build time = {end_time - start_time} secs')