From d009ead1011ebbd71701974467206e154413925f Mon Sep 17 00:00:00 2001 From: Wing Lian Date: Tue, 10 Dec 2024 16:25:25 -0500 Subject: [PATCH] fix build w pyproject to respect insalled torch version (#2168) * fix build w pyproject to respect insalled torch version * include in manifest * disable duplicate code check for now * move parser so it can be found * add checks for correct pytorch version so this doesn't slip by again --- .github/workflows/pypi.yml | 2 +- .github/workflows/tests-nightly.yml | 6 +- .github/workflows/tests.yml | 16 ++- MANIFEST.in | 1 + README.md | 8 +- cicd/Dockerfile.jinja | 4 +- cicd/cicd.sh | 2 + docker/Dockerfile | 4 +- docker/Dockerfile-tests | 4 +- docs/amd_hpc.qmd | 4 +- docs/debugging.qmd | 4 +- .../colab-axolotl-example.ipynb | 2 +- pyproject.toml | 7 ++ scripts/motd | 2 +- ...setuptools_axolotl_dynamic_dependencies.py | 104 ++++++++++++++++++ 15 files changed, 148 insertions(+), 22 deletions(-) create mode 100644 src/setuptools_axolotl_dynamic_dependencies.py diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 1be8b2cbf5..a98662c388 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -41,7 +41,7 @@ jobs: - name: Install dependencies run: | pip3 install wheel packaging - pip3 install -e . + pip3 install --no-build-isolation -e . pip3 install -r requirements-dev.txt -r requirements-tests.txt - name: Extract tag name diff --git a/.github/workflows/tests-nightly.yml b/.github/workflows/tests-nightly.yml index f3e5530cb8..7d83dd8e8d 100644 --- a/.github/workflows/tests-nightly.yml +++ b/.github/workflows/tests-nightly.yml @@ -60,11 +60,15 @@ jobs: run: | pip3 install --upgrade pip pip3 install --upgrade packaging - pip3 install -U -e . + pip3 install --no-build-isolation -U -e . python scripts/unsloth_install.py | sh python scripts/cutcrossentropy_install.py | sh pip3 install -r requirements-dev.txt -r requirements-tests.txt + - name: Make sure PyTorch version wasn't clobbered + run: | + python -c "import torch; assert '${{ matrix.pytorch_version }}' in torch.__version__" + - name: Ensure axolotl CLI was installed run: | axolotl --help diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 88172fdd5a..4a9c33c931 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -78,11 +78,15 @@ jobs: - name: Install dependencies run: | pip3 show torch - pip3 install -U -e . + pip3 install --no-build-isolation -U -e . python scripts/unsloth_install.py | sh python scripts/cutcrossentropy_install.py | sh pip3 install -r requirements-dev.txt -r requirements-tests.txt + - name: Make sure PyTorch version wasn't clobbered + run: | + python -c "import torch; assert '${{ matrix.pytorch_version }}' in torch.__version__" + - name: Ensure axolotl CLI was installed run: | axolotl --help @@ -120,7 +124,7 @@ jobs: - name: upgrade pip run: | pip3 install --upgrade pip - pip3 install --upgrade packaging setuptools wheel + pip3 install --upgrade packaging setuptools setuptools_scm build wheel - name: Install PyTorch run: | @@ -129,12 +133,16 @@ jobs: - name: Install dependencies run: | pip3 show torch - python3 setup.py sdist - pip3 install dist/axolotl*.tar.gz + python -m build --no-isolation --sdist + pip3 install --no-build-isolation dist/axolotl*.tar.gz python scripts/unsloth_install.py | sh python scripts/cutcrossentropy_install.py | sh pip3 install -r requirements-dev.txt -r requirements-tests.txt + - name: Make sure PyTorch version wasn't clobbered + run: | + python -c "import torch; assert '${{ matrix.pytorch_version }}' in torch.__version__" + - name: Ensure axolotl CLI was installed run: | axolotl --help diff --git a/MANIFEST.in b/MANIFEST.in index 215fa9a9d3..99324be3cd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include requirements.txt include README.md include LICENSE +include src/setuptools_axolotl_dynamic_dependencies.py recursive-include axolotl *.py diff --git a/README.md b/README.md index d4e48191e6..6afcaf1469 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Get started with Axolotl in just a few steps! This quickstart guide will walk yo **Requirements**: *Nvidia* GPU (Ampere architecture or newer for `bf16` and Flash Attention) or *AMD* GPU, Python >=3.10 and PyTorch >=2.3.1. ```bash -pip3 install axolotl[flash-attn,deepspeed] +pip3 install --no-build-isolation axolotl[flash-attn,deepspeed] # download examples and optionally deepspeed configs to the local path axolotl fetch examples @@ -131,7 +131,7 @@ from source. git clone https://github.com/axolotl-ai-cloud/axolotl.git cd axolotl pip3 install packaging ninja -pip3 install -e '.[flash-attn,deepspeed]' +pip3 install --no-build-isolation -e '.[flash-attn,deepspeed]' ``` ### Axolotl CLI Usage @@ -320,7 +320,7 @@ docker run --privileged --gpus '"all"' --shm-size 10g --rm -it --name axolotl -- 3. Install Axolotl along with python dependencies ```bash pip3 install packaging - pip3 install -e '.[flash-attn,deepspeed]' + pip3 install --no-build-isolation -e '.[flash-attn,deepspeed]' ``` 4. (Optional) Login to Huggingface to use gated models/datasets. ```bash @@ -399,7 +399,7 @@ Please use WSL or Docker! Use the below instead of the install method in QuickStart. ``` -pip3 install -e '.' +pip3 install --no-build-isolation -e '.' ``` More info: [mac.md](/docs/mac.qmd) diff --git a/cicd/Dockerfile.jinja b/cicd/Dockerfile.jinja index 4d1c4e664b..ed64664166 100644 --- a/cicd/Dockerfile.jinja +++ b/cicd/Dockerfile.jinja @@ -31,9 +31,9 @@ RUN if [ "$NIGHTLY_BUILD" = "true" ] ; then \ fi RUN if [ "$AXOLOTL_EXTRAS" != "" ] ; then \ - pip install -e .[deepspeed,flash-attn,optimizers,$AXOLOTL_EXTRAS] $AXOLOTL_ARGS; \ + pip install --no-build-isolation -e .[deepspeed,flash-attn,optimizers,$AXOLOTL_EXTRAS] $AXOLOTL_ARGS; \ else \ - pip install -e .[deepspeed,flash-attn,optimizers] $AXOLOTL_ARGS; \ + pip install --no-build-isolation -e .[deepspeed,flash-attn,optimizers] $AXOLOTL_ARGS; \ fi RUN python scripts/unsloth_install.py | sh diff --git a/cicd/cicd.sh b/cicd/cicd.sh index 1ead6d518e..88defdd0e4 100755 --- a/cicd/cicd.sh +++ b/cicd/cicd.sh @@ -1,6 +1,8 @@ #!/bin/bash set -e +python -c "import torch; assert '$PYTORCH_VERSION' in torch.__version__" + pytest -v --durations=10 -n8 --ignore=tests/e2e/ --ignore=tests/patched/ /workspace/axolotl/tests/ # pytest -v --durations=10 -n8 --dist loadfile /workspace/axolotl/tests/patched/ pytest -v --durations=10 -n1 --dist loadfile /workspace/axolotl/tests/e2e/patched/ diff --git a/docker/Dockerfile b/docker/Dockerfile index 261f0e12ad..6b6baf7515 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,9 +20,9 @@ WORKDIR /workspace/axolotl # If AXOLOTL_EXTRAS is set, append it in brackets RUN if [ "$AXOLOTL_EXTRAS" != "" ] ; then \ - pip install -e .[deepspeed,flash-attn,optimizers,$AXOLOTL_EXTRAS] $AXOLOTL_ARGS; \ + pip install --no-build-isolation -e .[deepspeed,flash-attn,optimizers,$AXOLOTL_EXTRAS] $AXOLOTL_ARGS; \ else \ - pip install -e .[deepspeed,flash-attn,optimizers] $AXOLOTL_ARGS; \ + pip install --no-build-isolation -e .[deepspeed,flash-attn,optimizers] $AXOLOTL_ARGS; \ fi RUN python scripts/unsloth_install.py | sh diff --git a/docker/Dockerfile-tests b/docker/Dockerfile-tests index 09efeb6199..8d97343597 100644 --- a/docker/Dockerfile-tests +++ b/docker/Dockerfile-tests @@ -24,9 +24,9 @@ RUN git fetch origin +$GITHUB_REF && \ # If AXOLOTL_EXTRAS is set, append it in brackets RUN if [ "$AXOLOTL_EXTRAS" != "" ] ; then \ - pip install -e .[deepspeed,flash-attn,mamba-ssm,$AXOLOTL_EXTRAS] $AXOLOTL_ARGS; \ + pip install --no-build-isolation -e .[deepspeed,flash-attn,mamba-ssm,$AXOLOTL_EXTRAS] $AXOLOTL_ARGS; \ else \ - pip install -e .[deepspeed,flash-attn,mamba-ssm] $AXOLOTL_ARGS; \ + pip install --no-build-isolation -e .[deepspeed,flash-attn,mamba-ssm] $AXOLOTL_ARGS; \ fi # So we can test the Docker image diff --git a/docs/amd_hpc.qmd b/docs/amd_hpc.qmd index d1c274e15a..70fbe88ee3 100644 --- a/docs/amd_hpc.qmd +++ b/docs/amd_hpc.qmd @@ -52,7 +52,7 @@ export GPU_ARCHS="gfx90a" cd flash-attention export PYTHON_SITE_PACKAGES=$(python -c 'import site; print(site.getsitepackages()[0])') patch "${PYTHON_SITE_PACKAGES}/torch/utils/hipify/hipify_python.py" hipify_patch.patch -pip install . +pip install --no-build-isolation . ``` ### 6. Install Axolotl @@ -63,7 +63,7 @@ Clone and install Axolotl: git clone https://github.com/axolotl-ai-cloud/axolotl cd axolotl pip install packaging ninja -pip install -e . +pip install --no-build-isolation -e . ``` ### 7. Apply xformers Workaround diff --git a/docs/debugging.qmd b/docs/debugging.qmd index d119dce18f..4eaa609272 100644 --- a/docs/debugging.qmd +++ b/docs/debugging.qmd @@ -71,7 +71,7 @@ Make sure you have an [editable install](https://setuptools.pypa.io/en/latest/us ```bash pip3 install packaging -pip3 install -e '.[flash-attn,deepspeed]' +pip3 install --no-build-isolation -e '.[flash-attn,deepspeed]' ``` #### Remote Hosts @@ -212,7 +212,7 @@ You will now be in the container. Next, perform an editable install of Axolotl: ```bash pip3 install packaging -pip3 install -e '.[flash-attn,deepspeed]' +pip3 install --no-build-isolation -e '.[flash-attn,deepspeed]' ``` ### Attach To Container diff --git a/examples/colab-notebooks/colab-axolotl-example.ipynb b/examples/colab-notebooks/colab-axolotl-example.ipynb index bfd1709a7f..0b373c28cf 100644 --- a/examples/colab-notebooks/colab-axolotl-example.ipynb +++ b/examples/colab-notebooks/colab-axolotl-example.ipynb @@ -24,7 +24,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install axolotl[deepspeed]" + "!pip install --no-build-isolation axolotl[deepspeed]" ] }, { diff --git a/pyproject.toml b/pyproject.toml index 6805e2e48f..016dbe4171 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,3 +17,10 @@ Homepage = "https://axolotl-ai-cloud.github.io/axolotl/" Repository = "https://github.com/axolotl-ai-cloud/axolotl.git" [tool.setuptools_scm] + +[tool.setuptools] +py-modules = ["setuptools_axolotl_dynamic_dependencies"] +include-package-data = true + +[tool.setuptools.cmdclass] +build_py = "setuptools_axolotl_dynamic_dependencies.BuildPyCommand" diff --git a/scripts/motd b/scripts/motd index 9d9edbd6d6..b3ffa165e6 100644 --- a/scripts/motd +++ b/scripts/motd @@ -13,5 +13,5 @@ cd /workspace rm -rf /workspace/axolotl git clone https://github.com/axolotl-ai-cloud/axolotl.git cd axolotl -pip install --no-deps -e . +pip install --no-build-isolation --no-deps -e . ``` diff --git a/src/setuptools_axolotl_dynamic_dependencies.py b/src/setuptools_axolotl_dynamic_dependencies.py new file mode 100644 index 0000000000..2f10efde68 --- /dev/null +++ b/src/setuptools_axolotl_dynamic_dependencies.py @@ -0,0 +1,104 @@ +""" +dynamic requirements for axolotl +""" +import platform +import re +from importlib.metadata import PackageNotFoundError, version + +from setuptools.command.build_py import build_py as _build_py + + +# pylint: disable=duplicate-code +def parse_requirements(): + _install_requires = [] + _dependency_links = [] + with open("./requirements.txt", encoding="utf-8") as requirements_file: + lines = [r.strip() for r in requirements_file.readlines()] + for line in lines: + is_extras = ( + "flash-attn" in line + or "flash-attention" in line + or "deepspeed" in line + or "mamba-ssm" in line + or "lion-pytorch" in line + ) + if line.startswith("--extra-index-url"): + # Handle custom index URLs + _, url = line.split() + _dependency_links.append(url) + elif not is_extras and line and line[0] != "#": + # Handle standard packages + _install_requires.append(line) + + try: + xformers_version = [req for req in _install_requires if "xformers" in req][0] + torchao_version = [req for req in _install_requires if "torchao" in req][0] + autoawq_version = [req for req in _install_requires if "autoawq" in req][0] + + if "Darwin" in platform.system(): + # don't install xformers on MacOS + _install_requires.pop(_install_requires.index(xformers_version)) + else: + # detect the version of torch already installed + # and set it so dependencies don't clobber the torch version + try: + torch_version = version("torch") + except PackageNotFoundError: + torch_version = "2.5.1" + _install_requires.append(f"torch=={torch_version}") + + version_match = re.match(r"^(\d+)\.(\d+)(?:\.(\d+))?", torch_version) + if version_match: + major, minor, patch = version_match.groups() + major, minor = int(major), int(minor) + patch = ( + int(patch) if patch is not None else 0 + ) # Default patch to 0 if not present + else: + raise ValueError("Invalid version format") + + if (major, minor) >= (2, 5): + _install_requires.pop(_install_requires.index(xformers_version)) + if patch == 0: + _install_requires.append("xformers==0.0.28.post2") + else: + _install_requires.append("xformers==0.0.28.post3") + _install_requires.pop(_install_requires.index(autoawq_version)) + elif (major, minor) >= (2, 4): + if patch == 0: + _install_requires.pop(_install_requires.index(xformers_version)) + _install_requires.append("xformers>=0.0.27") + else: + _install_requires.pop(_install_requires.index(xformers_version)) + _install_requires.append("xformers==0.0.28.post1") + elif (major, minor) >= (2, 3): + _install_requires.pop(_install_requires.index(torchao_version)) + if patch == 0: + _install_requires.pop(_install_requires.index(xformers_version)) + _install_requires.append("xformers>=0.0.26.post1") + else: + _install_requires.pop(_install_requires.index(xformers_version)) + _install_requires.append("xformers>=0.0.27") + elif (major, minor) >= (2, 2): + _install_requires.pop(_install_requires.index(torchao_version)) + _install_requires.pop(_install_requires.index(xformers_version)) + _install_requires.append("xformers>=0.0.25.post1") + else: + _install_requires.pop(_install_requires.index(torchao_version)) + _install_requires.pop(_install_requires.index(xformers_version)) + _install_requires.append("xformers>=0.0.23.post1") + + except PackageNotFoundError: + pass + return _install_requires, _dependency_links + + +class BuildPyCommand(_build_py): + """ + custom build_py command to parse dynamic requirements + """ + + def finalize_options(self): + super().finalize_options() + install_requires, _ = parse_requirements() + self.distribution.install_requires = install_requires