diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 041093f..93f8389 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,29 +17,14 @@ jobs: run: | gh release create "${{ github.ref_name }}" \ --title "${{ github.ref_name }}" \ - --notes "## Linux x86_64 - - | Flash-Attention | Python | PyTorch | CUDA | - | --- | --- | --- | --- | - | 2.7.4 | 3.10, 3.11, 3.12 | 2.5.1, 2.6.0, 2.7.1, 2.8.0 | 12.4.1, 12.8.1, 12.9.1 | - - ## Windows x86_64 - - | Flash-Attention | Python | PyTorch | CUDA | - | --- | --- | --- | --- | - | 2.6.3, 2.7.4, 2.8.2 | 3.10, 3.11, 3.12 | 2.5.1, 2.6.0, 2.7.1, 2.8.0 | 12.4.1, 12.8.1 | - " + --notes "TBD" # ######################################################### # Build wheels with GitHub hosted runner # ######################################################### - build_wheels: - name: Build wheels and Upload (Linux x86_64, GitHub hosted runner) + build_wheels_linux: + name: Build Linux needs: create_releases - runs-on: ubuntu-22.04 - env: - DEBIAN_FRONTEND: noninteractive - TERM: xterm-256color strategy: fail-fast: false matrix: @@ -76,93 +61,19 @@ jobs: cuda-version: "12.9.1" - torch-version: "2.7.1" cuda-version: "12.9.1" - steps: - - uses: actions/checkout@v4 + # flash-attn 2.7.4 does not build in GitHub Hosted Runner + - flash-attn-version: "2.7.4" + uses: ./.github/workflows/build_linux.yml + with: + flash-attn-version: ${{ matrix.flash-attn-version }} + python-version: ${{ matrix.python-version }} + torch-version: ${{ matrix.torch-version }} + cuda-version: ${{ matrix.cuda-version }} + secrets: inherit - - name: Maximize build space - run: | - df -h - echo "-----------------------------" - sudo rm -rf /usr/share/dotnet - sudo rm -rf /usr/local/lib/android - sudo rm -rf /opt/ghc - sudo rm -rf /opt/hostedtoolcache/CodeQL - df -h - - - name: Set Swap Space - uses: pierotofy/set-swap-space@master - with: - swap-size-gb: 48 - - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - uses: Jimver/cuda-toolkit@master - with: - cuda: ${{ matrix.cuda-version }} - sub-packages: '["nvcc", "toolkit"]' - method: "network" - use-github-cache: false - use-local-cache: false - - - name: Install build dependencies - run: | - sudo apt install -y ninja-build clang - pip install -U pip setuptools==75.8.0 wheel setuptools packaging psutil - - - name: Set environment variables - run: | - export PATH=/usr/local/nvidia/bin:/usr/local/nvidia/lib64:$PATH - export LD_LIBRARY_PATH=/usr/local/nvidia/lib64:/usr/local/cuda/lib64:$LD_LIBRARY_PATH - - - name: Build wheels - env: - MAX_JOBS: 2 - NVCC_THREADS: 2 - run: | - chmod +x build_linux.sh - ./build_linux.sh ${{ matrix.flash-attn-version }} ${{ matrix.python-version }} ${{ matrix.torch-version }} ${{ matrix.cuda-version }} - wheel_name=$(basename $(ls flash-attention/dist/*.whl | head -n 1)) - echo "wheel_name=$wheel_name" >> $GITHUB_ENV - - - name: Install Test - run: | - pip install --no-cache-dir flash-attention/dist/${{ env.wheel_name }} - python -c "import flash_attn; print(flash_attn.__version__)" - - - name: Upload Release Asset - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - tag_name=${{ github.ref_name }} - wheel_path="flash-attention/dist/${{ env.wheel_name }}" - - # Check if the file exists - if [ ! -f "$wheel_path" ]; then - echo "Error: Wheel file not found at $wheel_path" - exit 1 - fi - - # Upload the release asset using GitHub CLI - gh release upload "$tag_name" "$wheel_path" --clobber - - # ######################################################### - # Build wheels with self-hosted runner - # ######################################################### - build_wheels_self_hosted: - name: Build wheels and Upload (Linux x86_64, self-hosted runner) + build_wheels_linux_self_hosted: + name: Build Linux (self-hosted) needs: create_releases - runs-on: self-hosted - container: - image: ubuntu:22.04 - defaults: - run: - shell: bash - env: - DEBIAN_FRONTEND: noninteractive - TERM: xterm-256color - timeout-minutes: 2000 strategy: fail-fast: false matrix: @@ -192,9 +103,6 @@ jobs: # torch 2.7.0 does not support CUDA 12.4 - torch-version: "2.7.0" cuda-version: "12.4.1" - # flash-attn 2.7.4 does not build with CUDA 12.8 - - flash-attn-version: "2.7.4" - cuda-version: "12.8.1" # torch < 2.8 does not support CUDA 12.9 - torch-version: "2.5.1" cuda-version: "12.9.1" @@ -202,119 +110,17 @@ jobs: cuda-version: "12.9.1" - torch-version: "2.7.1" cuda-version: "12.9.1" - steps: - - name: Install tools - shell: bash - run: | - apt-get update && apt-get install -y --no-install-recommends \ - curl \ - ca-certificates \ - sudo \ - software-properties-common \ - wget \ - unzip \ - zip \ - git \ - build-essential \ - gcc \ - g++ \ - clang \ - ninja-build \ - keyboard-configuration + uses: ./.github/workflows/build_linux_self_host.yml + with: + flash-attn-version: ${{ matrix.flash-attn-version }} + python-version: ${{ matrix.python-version }} + torch-version: ${{ matrix.torch-version }} + cuda-version: ${{ matrix.cuda-version }} + secrets: inherit - - name: Install gh - shell: bash - run: | - sudo mkdir -p -m 755 /etc/apt/keyrings - out=$(mktemp) - wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg - cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null - sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - sudo apt update - sudo apt install gh -y - - - uses: actions/checkout@v4 - - - name: Configure Git safe directory - shell: bash - run: | - git config --global --add safe.directory $(pwd) - - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - uses: Jimver/cuda-toolkit@master - with: - cuda: ${{ matrix.cuda-version }} - sub-packages: '["nvcc", "toolkit"]' - method: "network" - use-github-cache: false - use-local-cache: false - - - name: Install build dependencies - shell: bash - run: | - sudo apt install -y ninja-build clang - pip install -U pip setuptools==75.8.0 wheel setuptools packaging psutil - - - name: Set environment variables - shell: bash - run: | - export PATH=/usr/local/nvidia/bin:/usr/local/nvidia/lib64:$PATH - export LD_LIBRARY_PATH=/usr/local/nvidia/lib64:/usr/local/cuda/lib64:$LD_LIBRARY_PATH - - - name: Build wheels - timeout-minutes: 1200 - shell: bash - env: - MAX_JOBS: 2 - NVCC_THREADS: 2 - run: | - chmod +x build_linux.sh - ./build_linux.sh ${{ matrix.flash-attn-version }} ${{ matrix.python-version }} ${{ matrix.torch-version }} ${{ matrix.cuda-version }} - wheel_name=$(basename $(ls flash-attention/dist/*.whl | head -n 1)) - echo "wheel_name=$wheel_name" >> $GITHUB_ENV - - - name: Install Test - shell: bash - run: | - pip uninstall -y flash-attn > /dev/null 2>&1 - pip install --no-cache-dir flash-attention/dist/${{ env.wheel_name }} - python -c "import flash_attn; print(flash_attn.__version__)" - - - name: Upload Release Asset - shell: bash - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - tag_name=${{ github.ref_name }} - wheel_path="flash-attention/dist/${{ env.wheel_name }}" - - # Check if the file exists - if [ ! -f "$wheel_path" ]; then - echo "Error: Wheel file not found at $wheel_path" - exit 1 - fi - - # Upload the release asset using GitHub CLI - gh release upload "$tag_name" "$wheel_path" --clobber - - - name: Clean up - shell: bash - if: always() - run: | - rm -rf /opt/hostedtoolcache/Python - - build_windows_wheels: - name: Build wheels and Upload (Windows x86_64, GitHub hosted runner) - runs-on: windows-2022 - timeout-minutes: 1000 + build_wheels_windows: + name: Build Windows needs: create_releases - env: - MAX_JOBS: 2 - NVCC_THREADS: 2 strategy: fail-fast: false matrix: @@ -344,9 +150,6 @@ jobs: # torch 2.7.0 does not support CUDA 12.4 - torch-version: "2.7.0" cuda-version: "12.4.1" - # flash-attn 2.7.4 does not build with CUDA 12.8 - - flash-attn-version: "2.7.4" - cuda-version: "12.8.1" # torch < 2.8 does not support CUDA 12.9 - torch-version: "2.5.1" cuda-version: "12.9.1" @@ -354,67 +157,31 @@ jobs: cuda-version: "12.9.1" - torch-version: "2.7.1" cuda-version: "12.9.1" + uses: ./.github/workflows/build_windows.yml + with: + flash-attn-version: ${{ matrix.flash-attn-version }} + python-version: ${{ matrix.python-version }} + torch-version: ${{ matrix.torch-version }} + cuda-version: ${{ matrix.cuda-version }} + secrets: inherit + + update_release_notes: + name: Update Release Notes + needs: + [build_wheels_linux, build_wheels_linux_self_hosted, build_wheels_windows] + if: always() + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Enable Git long paths - shell: pwsh - run: git config --system core.longpaths true - - uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} + python-version: 3.12 - - uses: Jimver/cuda-toolkit@v0.2.24 - with: - cuda: ${{ matrix.cuda-version }} - method: "network" - use-github-cache: false - use-local-cache: false - - - name: Install VS2022 BuildTools - shell: pwsh - run: | - choco install -y visualstudio2022buildtools ` - --version=117.14.1 ` - --params "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64" - - - name: Install build dependencies - shell: pwsh - run: | - python -m pip install -U setuptools==75.8.0 wheel packaging psutil ninja - - - name: Build wheels - shell: pwsh - run: | - .\build_windows.ps1 -FlashAttnVersion "${{ matrix.flash-attn-version }}" -PythonVersion "${{ matrix.python-version }}" -TorchVersion "${{ matrix.torch-version }}" -CudaVersion "${{ matrix.cuda-version }}" - $wheelName = Get-ChildItem -Path "flash-attention\dist\*.whl" | Select-Object -First 1 | ForEach-Object { $_.Name } - echo "wheel_name=$wheelName" >> $env:GITHUB_ENV - - - name: Install Test - shell: pwsh - run: | - pip install --no-cache-dir flash-attention/dist/$env:wheel_name - python -c "import flash_attn; print(flash_attn.__version__)" - - - name: Upload Release Asset - shell: pwsh + - name: Generate Release Notes env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - $tag_name = "${env:GITHUB_REF}".Replace("refs/tags/", "") - $wheel_path = "flash-attention/dist/$env:wheel_name" - - # Check if the file exists - if (-not (Test-Path $wheel_path)) { - $tag_name = "${env:GITHUB_REF}".Replace("refs/tags/", "") - $wheel_path = "flash-attention/dist/$env:wheel_name" - - # Check if the file exists - if (-not (Test-Path $wheel_path)) { - Write-Host "Error: Wheel file not found at $wheel_path" - exit 1 - } - - # Upload the release asset using GitHub CLI - gh release upload "$tag_name" "$wheel_path" --clobber + gh release view "${{ github.ref_name }}" --json assets > /tmp/assets.json + python create_release_note.py /tmp/assets.json > /tmp/release_notes.md + gh release edit "${{ github.ref_name }}" --notes-file /tmp/release_notes.md diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 0e3af41..7cc61f7 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -2,7 +2,7 @@ # Build wheels with GitHub hosted runner # ######################################################### -name: Build wheels and upload to GitHub Releases (Linux x86_64) +name: "[Linux x86_64] Build wheels and upload to GitHub Releases" on: workflow_call: diff --git a/.github/workflows/build_linux_self_host.yml b/.github/workflows/build_linux_self_host.yml index a97ba63..4d7b81c 100644 --- a/.github/workflows/build_linux_self_host.yml +++ b/.github/workflows/build_linux_self_host.yml @@ -2,7 +2,7 @@ # Build wheels with self-hosted runner # ######################################################### -name: Build wheels and upload to GitHub Releases (Linux x86_64, self-hosted runner) +name: "[Linux x86_64, self-hosted runner] Build wheels and upload to GitHub Releases" on: workflow_call: @@ -105,8 +105,8 @@ jobs: id: build_wheels shell: bash env: - MAX_JOBS: 2 - NVCC_THREADS: 2 + MAX_JOBS: 3 + NVCC_THREADS: 3 run: | chmod +x build_linux.sh ./build_linux.sh ${{ inputs.flash-attn-version }} ${{ inputs.python-version }} ${{ inputs.torch-version }} ${{ inputs.cuda-version }} diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml deleted file mode 100644 index d590f30..0000000 --- a/.github/workflows/build_test.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Build wheels and upload to GitHub Releases - -on: - workflow_dispatch: - -jobs: - # ######################################################### - # Build wheels with GitHub hosted runner - # ######################################################### - build_wheels_linux: - name: Build Linux - strategy: - fail-fast: false - matrix: - flash-attn-version: ["2.6.3"] - python-version: ["3.10"] - torch-version: ["2.5.1"] - # https://developer.nvidia.com/cuda-toolkit-archive - cuda-version: ["12.4.1"] - uses: ./.github/workflows/build_linux.yml - with: - flash-attn-version: ${{ matrix.flash-attn-version }} - python-version: ${{ matrix.python-version }} - torch-version: ${{ matrix.torch-version }} - cuda-version: ${{ matrix.cuda-version }} - secrets: inherit - - build_wheels_windows: - name: Build Windows - strategy: - fail-fast: false - matrix: - flash-attn-version: ["2.6.3"] - python-version: ["3.10"] - torch-version: ["2.5.1"] - # https://developer.nvidia.com/cuda-toolkit-archive - cuda-version: ["12.4.1"] - uses: ./.github/workflows/build_windows.yml - with: - flash-attn-version: ${{ matrix.flash-attn-version }} - python-version: ${{ matrix.python-version }} - torch-version: ${{ matrix.torch-version }} - cuda-version: ${{ matrix.cuda-version }} - secrets: inherit diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 55bf9dd..cf5016c 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -2,7 +2,7 @@ # Build wheels with GitHub hosted runner on Windows x86_64 # ######################################################### -name: Build wheels and upload to GitHub Releases (Windows x86_64) +name: "[Windows x86_64] Build wheels and upload to GitHub Releases" on: workflow_call: diff --git a/create_release_note.py b/create_release_note.py new file mode 100644 index 0000000..6feed1b --- /dev/null +++ b/create_release_note.py @@ -0,0 +1,122 @@ +import json +import re +import sys +from pathlib import Path + + +def parse_wheel_filename(filename): + """ + Wheel filename から情報を抽出 + 例: flash_attn-2.6.3+cu124torch2.5-cp311-cp311-linux_x86_64.whl + flash_attn-2.7.4+cu124torch2.6-cp311-cp311-linux_x86_64.whl + """ + # Flash Attention wheelのパターンに合わせて正規表現を調整 + # PyTorchバージョンはパッチバージョンなしの形式 (例: torch2.5) + pattern = ( + r"flash_attn-(\d+\.\d+\.\d+)\+cu(\d+)torch(\d+\.\d+)-cp(\d+)-cp\d+-(\w+)\.whl" + ) + match = re.match(pattern, filename) + + if match: + flash_version = match.group(1) + cuda_version = f"{match.group(2)[:2]}.{match.group(2)[2:]}" # 124 -> 12.4 + torch_version = match.group(3) + python_version = f"{match.group(4)[:1]}.{match.group(4)[1:]}" # 311 -> 3.11 + platform = match.group(5) # linux, win32など + + return { + "flash_version": flash_version, + "cuda_version": cuda_version, + "torch_version": torch_version, + "python_version": python_version, + "platform": platform, + } + return None + + +def generate_release_notes_from_assets(assets_info: dict): + assets_names = [ + asset["name"] for asset in assets_info if asset["name"].endswith(".whl") + ] + if len(assets_names) == 0: + sys.exit(1) + + assets_dict = {} + + for asset_name in assets_names: + asset_info = parse_wheel_filename(asset_name) + if asset_info is None: + continue + + if asset_info["platform"] not in assets_dict: + assets_dict[asset_info["platform"]] = { + "flash_versions": set(), + "python_versions": set(), + "torch_versions": set(), + "cuda_versions": set(), + } + assets_dict[asset_info["platform"]]["flash_versions"].add( + asset_info["flash_version"] + ) + assets_dict[asset_info["platform"]]["python_versions"].add( + asset_info["python_version"] + ) + assets_dict[asset_info["platform"]]["torch_versions"].add( + asset_info["torch_version"] + ) + assets_dict[asset_info["platform"]]["cuda_versions"].add( + asset_info["cuda_version"] + ) + + notes = [] + + for platform_name, data in sorted(assets_dict.items()): + if any(len(data[key]) == 0 for key in data): + continue + + platform_name = platform_name[:1].upper() + platform_name[1:] + platform_name = platform_name.replace("_", " ", 1) + + notes.append(f"## {platform_name}") + notes.append("") + notes.append("| Flash-Attention | Python | PyTorch | CUDA |") + notes.append("| --- | --- | --- | --- |") + + flash_versions = ", ".join(sorted(data["flash_versions"])) + python_versions = ", ".join(sorted(data["python_versions"])) + torch_versions = ", ".join(sorted(data["torch_versions"])) + cuda_versions = ", ".join(sorted(data["cuda_versions"])) + + notes.append( + f"| {flash_versions} | {python_versions} | {torch_versions} | {cuda_versions} |" + ) + notes.append("") + + return "\n".join(notes) + + +def main(): + try: + if len(sys.argv) != 2: + sys.exit(1) + + assets_json_path = Path(sys.argv[1]) + if not assets_json_path.exists(): + sys.exit(1) + + with open(assets_json_path, "r") as f: + assets_info = json.load(f)["assets"] + + if len(assets_info) == 0: + sys.exit(1) + + text = generate_release_notes_from_assets(assets_info) + if text: + print(text) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main()