diff --git a/.github/workflows/pr_tests_gpu.yml b/.github/workflows/pr_tests_gpu.yml new file mode 100644 index 000000000000..a06689b5fad7 --- /dev/null +++ b/.github/workflows/pr_tests_gpu.yml @@ -0,0 +1,241 @@ +name: Fast GPU Tests on PR + +on: + pull_request: + branches: main + paths: + - "src/diffusers/models/modeling_utils.py" + - "src/diffusers/models/model_loading_utils.py" + - "src/diffusers/pipelines/pipeline_utils.py" + - "src/diffusers/pipeline_loading_utils.py" + - "src/diffusers/loaders/lora_base.py" + - "src/diffusers/loaders/lora_pipeline.py" + - "src/diffusers/loaders/peft.py" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + DIFFUSERS_IS_CI: yes + OMP_NUM_THREADS: 8 + MKL_NUM_THREADS: 8 + HF_HUB_ENABLE_HF_TRANSFER: 1 + PYTEST_TIMEOUT: 600 + PIPELINE_USAGE_CUTOFF: 1000000000 # set high cutoff so that only always-test pipelines run + +jobs: + setup_torch_cuda_pipeline_matrix: + name: Setup Torch Pipelines CUDA Slow Tests Matrix + runs-on: + group: aws-general-8-plus + container: + image: diffusers/diffusers-pytorch-cpu + outputs: + pipeline_test_matrix: ${{ steps.fetch_pipeline_matrix.outputs.pipeline_test_matrix }} + steps: + - name: Checkout diffusers + uses: actions/checkout@v3 + with: + fetch-depth: 2 + - name: Install dependencies + run: | + python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH" + python -m uv pip install -e [quality,test] + - name: Environment + run: | + python utils/print_env.py + - name: Fetch Pipeline Matrix + id: fetch_pipeline_matrix + run: | + matrix=$(python utils/fetch_torch_cuda_pipeline_test_matrix.py) + echo $matrix + echo "pipeline_test_matrix=$matrix" >> $GITHUB_OUTPUT + - name: Pipeline Tests Artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: test-pipelines.json + path: reports + + torch_pipelines_cuda_tests: + name: Torch Pipelines CUDA Tests + needs: setup_torch_cuda_pipeline_matrix + strategy: + fail-fast: false + max-parallel: 8 + matrix: + module: ${{ fromJson(needs.setup_torch_cuda_pipeline_matrix.outputs.pipeline_test_matrix) }} + runs-on: + group: aws-g4dn-2xlarge + container: + image: diffusers/diffusers-pytorch-cuda + options: --shm-size "16gb" --ipc host --gpus 0 + steps: + - name: Checkout diffusers + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: NVIDIA-SMI + run: | + nvidia-smi + - name: Install dependencies + run: | + python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH" + python -m uv pip install -e [quality,test] + pip uninstall accelerate -y && python -m uv pip install -U accelerate@git+https://github.com/huggingface/accelerate.git + pip uninstall transformers -y && python -m uv pip install -U transformers@git+https://github.com/huggingface/transformers.git --no-deps + + - name: Environment + run: | + python utils/print_env.py + - name: Extract tests + id: extract_tests + run: | + pattern=$(python utils/extract_tests_from_mixin.py --type pipeline) + echo "$pattern" > /tmp/test_pattern.txt + echo "pattern_file=/tmp/test_pattern.txt" >> $GITHUB_OUTPUT + + - name: PyTorch CUDA checkpoint tests on Ubuntu + env: + HF_TOKEN: ${{ secrets.DIFFUSERS_HF_HUB_READ_TOKEN }} + # https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms + CUBLAS_WORKSPACE_CONFIG: :16:8 + run: | + pattern=$(cat ${{ steps.extract_tests.outputs.pattern_file }}) + python -m pytest -n 1 --max-worker-restart=0 --dist=loadfile \ + -s -v -k "not Flax and not Onnx and $pattern" \ + --make-reports=tests_pipeline_${{ matrix.module }}_cuda \ + tests/pipelines/${{ matrix.module }} + + - name: Failure short reports + if: ${{ failure() }} + run: | + cat reports/tests_pipeline_${{ matrix.module }}_cuda_stats.txt + cat reports/tests_pipeline_${{ matrix.module }}_cuda_failures_short.txt + - name: Test suite reports artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: pipeline_${{ matrix.module }}_test_reports + path: reports + + torch_cuda_tests: + name: Torch CUDA Tests + runs-on: + group: aws-g4dn-2xlarge + container: + image: diffusers/diffusers-pytorch-cuda + options: --shm-size "16gb" --ipc host --gpus 0 + defaults: + run: + shell: bash + strategy: + fail-fast: false + max-parallel: 2 + matrix: + module: [models, schedulers, lora, others] + steps: + - name: Checkout diffusers + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: Install dependencies + run: | + python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH" + python -m uv pip install -e [quality,test] + python -m uv pip install peft@git+https://github.com/huggingface/peft.git + pip uninstall accelerate -y && python -m uv pip install -U accelerate@git+https://github.com/huggingface/accelerate.git + pip uninstall transformers -y && python -m uv pip install -U transformers@git+https://github.com/huggingface/transformers.git --no-deps + + - name: Environment + run: | + python utils/print_env.py + + - name: Extract tests + id: extract_tests + run: | + pattern=$(python utils/extract_tests_from_mixin.py --type ${{ matrix.module }}) + echo "$pattern" > /tmp/test_pattern.txt + echo "pattern_file=/tmp/test_pattern.txt" >> $GITHUB_OUTPUT + + - name: Run PyTorch CUDA tests + env: + HF_TOKEN: ${{ secrets.DIFFUSERS_HF_HUB_READ_TOKEN }} + # https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms + CUBLAS_WORKSPACE_CONFIG: :16:8 + run: | + pattern=$(cat ${{ steps.extract_tests.outputs.pattern_file }}) + if [ -z "$pattern" ]; then + python -m pytest -n 1 -sv --max-worker-restart=0 --dist=loadfile -k "not Flax and not Onnx" tests/${{ matrix.module }} \ + --make-reports=tests_torch_cuda_${{ matrix.module }} + else + python -m pytest -n 1 -sv --max-worker-restart=0 --dist=loadfile -k "not Flax and not Onnx and $pattern" tests/${{ matrix.module }} \ + --make-reports=tests_torch_cuda_${{ matrix.module }} + fi + + - name: Failure short reports + if: ${{ failure() }} + run: | + cat reports/tests_torch_cuda_${{ matrix.module }}_stats.txt + cat reports/tests_torch_cuda_${{ matrix.module }}_failures_short.txt + + - name: Test suite reports artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: torch_cuda_test_reports_${{ matrix.module }} + path: reports + + run_examples_tests: + name: Examples PyTorch CUDA tests on Ubuntu + pip uninstall transformers -y && python -m uv pip install -U transformers@git+https://github.com/huggingface/transformers.git --no-deps + runs-on: + group: aws-g4dn-2xlarge + + container: + image: diffusers/diffusers-pytorch-cuda + options: --gpus 0 --shm-size "16gb" --ipc host + steps: + - name: Checkout diffusers + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: NVIDIA-SMI + run: | + nvidia-smi + - name: Install dependencies + run: | + python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH" + python -m uv pip install -e [quality,test,training] + + - name: Environment + run: | + python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH" + python utils/print_env.py + + - name: Run example tests on GPU + env: + HF_TOKEN: ${{ secrets.DIFFUSERS_HF_HUB_READ_TOKEN }} + run: | + python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH" + python -m uv pip install timm + python -m pytest -n 1 --max-worker-restart=0 --dist=loadfile -s -v --make-reports=examples_torch_cuda examples/ + + - name: Failure short reports + if: ${{ failure() }} + run: | + cat reports/examples_torch_cuda_stats.txt + cat reports/examples_torch_cuda_failures_short.txt + + - name: Test suite reports artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: examples_test_reports + path: reports + diff --git a/.github/workflows/push_tests.yml b/.github/workflows/push_tests.yml index 315375ee51fd..abf825eaa7a0 100644 --- a/.github/workflows/push_tests.yml +++ b/.github/workflows/push_tests.yml @@ -1,13 +1,6 @@ name: Fast GPU Tests on main on: - pull_request: - branches: main - paths: - - "src/diffusers/models/modeling_utils.py" - - "src/diffusers/models/model_loading_utils.py" - - "src/diffusers/pipelines/pipeline_utils.py" - - "src/diffusers/pipeline_loading_utils.py" workflow_dispatch: push: branches: @@ -167,7 +160,6 @@ jobs: path: reports flax_tpu_tests: - if: ${{ github.event_name != 'pull_request' }} name: Flax TPU Tests runs-on: group: gcp-ct5lp-hightpu-8t @@ -216,7 +208,6 @@ jobs: path: reports onnx_cuda_tests: - if: ${{ github.event_name != 'pull_request' }} name: ONNX CUDA Tests runs-on: group: aws-g4dn-2xlarge @@ -265,7 +256,6 @@ jobs: path: reports run_torch_compile_tests: - if: ${{ github.event_name != 'pull_request' }} name: PyTorch Compile CUDA tests runs-on: @@ -309,7 +299,6 @@ jobs: path: reports run_xformers_tests: - if: ${{ github.event_name != 'pull_request' }} name: PyTorch xformers CUDA tests runs-on: diff --git a/utils/extract_tests_from_mixin.py b/utils/extract_tests_from_mixin.py new file mode 100644 index 000000000000..c8b65b96ee16 --- /dev/null +++ b/utils/extract_tests_from_mixin.py @@ -0,0 +1,61 @@ +import argparse +import inspect +import sys +from pathlib import Path +from typing import List, Type + + +root_dir = Path(__file__).parent.parent.absolute() +sys.path.insert(0, str(root_dir)) + +parser = argparse.ArgumentParser() +parser.add_argument("--type", type=str, default=None) +args = parser.parse_args() + + +def get_test_methods_from_class(cls: Type) -> List[str]: + """ + Get all test method names from a given class. + Only returns methods that start with 'test_'. + """ + test_methods = [] + for name, obj in inspect.getmembers(cls): + if name.startswith("test_") and inspect.isfunction(obj): + test_methods.append(name) + return sorted(test_methods) + + +def generate_pytest_pattern(test_methods: List[str]) -> str: + """Generate pytest pattern string for the -k flag.""" + return " or ".join(test_methods) + + +def generate_pattern_for_mixin(mixin_class: Type) -> str: + """ + Generate pytest pattern for a specific mixin class. + """ + if mixin_cls is None: + return "" + test_methods = get_test_methods_from_class(mixin_class) + return generate_pytest_pattern(test_methods) + + +if __name__ == "__main__": + mixin_cls = None + if args.type == "pipeline": + from tests.pipelines.test_pipelines_common import PipelineTesterMixin + + mixin_cls = PipelineTesterMixin + + elif args.type == "models": + from tests.models.test_modeling_common import ModelTesterMixin + + mixin_cls = ModelTesterMixin + + elif args.type == "lora": + from tests.lora.utils import PeftLoraLoaderMixinTests + + mixin_cls = PeftLoraLoaderMixinTests + + pattern = generate_pattern_for_mixin(mixin_cls) + print(pattern)